[pypy-svn] pypy arm-backend-2: merge default
bivab
commits-noreply at bitbucket.org
Wed Feb 2 13:50:12 CET 2011
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r41549:7c31324be2de
Date: 2011-01-25 10:13 +0100
http://bitbucket.org/pypy/pypy/changeset/7c31324be2de/
Log: merge default
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
@@ -80,11 +80,11 @@
# ____________________________________________________________
-def compile_new_loop(metainterp, old_loop_tokens, greenkey, start,
- full_preamble_needed=True):
+def compile_new_loop(metainterp, old_loop_tokens, greenkey, start, start_resumedescr):
"""Try to compile a new loop by closing the current history back
to the first operation.
"""
+ full_preamble_needed=True
history = metainterp.history
loop = create_empty_loop(metainterp)
loop.inputargs = history.inputargs
@@ -102,6 +102,7 @@
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
try:
old_loop_token = jitdriver_sd.warmstate.optimize_loop(
@@ -390,6 +391,12 @@
self.copy_all_attrbutes_into(res)
return res
+class ResumeAtPositionDescr(ResumeGuardDescr):
+ def _clone_if_mutable(self):
+ res = ResumeAtPositionDescr()
+ self.copy_all_attrbutes_into(res)
+ return res
+
class ResumeGuardForcedDescr(ResumeGuardDescr):
def __init__(self, metainterp_sd, jitdriver_sd):
@@ -574,10 +581,14 @@
new_loop.operations = [op.clone() for op in metainterp.history.operations]
metainterp_sd = metainterp.staticdata
state = metainterp.jitdriver_sd.warmstate
+ if isinstance(resumekey, ResumeAtPositionDescr):
+ inline_short_preamble = False
+ else:
+ inline_short_preamble = True
try:
target_loop_token = state.optimize_bridge(metainterp_sd,
old_loop_tokens,
- new_loop)
+ new_loop, inline_short_preamble)
except InvalidLoop:
# XXX I am fairly convinced that optimize_bridge cannot actually raise
# InvalidLoop
@@ -588,34 +599,9 @@
# know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
prepare_last_operation(new_loop, target_loop_token)
resumekey.compile_and_attach(metainterp, new_loop)
- compile_known_target_bridges(metainterp, new_loop)
record_loop_or_bridge(metainterp_sd, new_loop)
return target_loop_token
-# For backends that not supports emitting guards with preset jump
-# targets, emit mini-bridges containing the jump
-def compile_known_target_bridges(metainterp, bridge):
- for op in bridge.operations:
- if op.is_guard():
- target = op.getjumptarget()
- if target:
- mini = create_empty_loop(metainterp, 'fallback')
- mini.inputargs = op.getfailargs()[:]
- jmp = ResOperation(rop.JUMP, mini.inputargs[:], None, target)
- mini.operations = [jmp]
- descr = op.getdescr()
- assert isinstance(descr, ResumeGuardDescr)
- mini.token = bridge.token
-
- #descr.compile_and_attach(metainterp, mini)
- if not we_are_translated():
- descr._debug_suboperations = mini.operations
- send_bridge_to_backend(metainterp.staticdata, descr,
- mini.inputargs, mini.operations,
- bridge.token)
- record_loop_or_bridge(metainterp.staticdata, mini)
-
-
def prepare_last_operation(new_loop, target_loop_token):
op = new_loop.operations[-1]
if not isinstance(target_loop_token, TerminatingLoopToken):
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -10,9 +10,9 @@
# the 'extraeffect' field is one of the following values:
EF_PURE = 0 #pure function (and cannot raise)
- EF_CANNOT_RAISE = 1 #a function which cannot raise
- EF_CAN_RAISE = 2 #normal function (can raise)
- EF_LOOPINVARIANT = 3 #special: call it only once per loop
+ EF_LOOPINVARIANT = 1 #special: call it only once per loop
+ EF_CANNOT_RAISE = 2 #a function which cannot raise
+ EF_CAN_RAISE = 3 #normal function (can raise)
EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 4 #can raise and force virtualizables
# the 'oopspecindex' field is one of the following values:
@@ -60,8 +60,13 @@
return cls._cache[key]
result = object.__new__(cls)
result.readonly_descrs_fields = readonly_descrs_fields
- result.write_descrs_fields = write_descrs_fields
- result.write_descrs_arrays = write_descrs_arrays
+ if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
+ extraeffect == EffectInfo.EF_PURE:
+ result.write_descrs_fields = []
+ result.write_descrs_arrays = []
+ else:
+ result.write_descrs_fields = write_descrs_fields
+ result.write_descrs_arrays = write_descrs_arrays
result.extraeffect = extraeffect
result.oopspecindex = oopspecindex
cls._cache[key] = result
diff --git a/pypy/translator/c/test/test_dtoa.py b/pypy/translator/c/test/test_dtoa.py
deleted file mode 100644
--- a/pypy/translator/c/test/test_dtoa.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from __future__ import with_statement
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.tool.autopath import pypydir
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib.rstring import StringBuilder
-import py
-
-includes = []
-libraries = []
-
-cdir = py.path.local(pypydir) / 'translator' / 'c'
-files = [cdir / 'src' / 'dtoa.c']
-include_dirs = [cdir]
-
-eci = ExternalCompilationInfo(
- include_dirs = include_dirs,
- libraries = libraries,
- separate_module_files = files,
- separate_module_sources = ['''
- #include <stdlib.h>
- #include <assert.h>
- #define WITH_PYMALLOC
- #include "src/obmalloc.c"
- '''],
- export_symbols = ['_Py_dg_strtod',
- '_Py_dg_dtoa',
- '_Py_dg_freedtoa',
- ],
-)
-
-dg_strtod = rffi.llexternal(
- '_Py_dg_strtod', [rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE,
- compilation_info=eci)
-
-dg_dtoa = rffi.llexternal(
- '_Py_dg_dtoa', [rffi.DOUBLE, rffi.INT, rffi.INT,
- rffi.INTP, rffi.INTP, rffi.CCHARPP], rffi.CCHARP,
- compilation_info=eci)
-
-dg_freedtoa = rffi.llexternal(
- '_Py_dg_freedtoa', [rffi.CCHARP], lltype.Void,
- compilation_info=eci)
-
-def strtod(input):
- with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as end_ptr:
- with rffi.scoped_str2charp(input) as ll_input:
- result = dg_strtod(ll_input, end_ptr)
- if end_ptr[0] and ord(end_ptr[0][0]):
- offset = (rffi.cast(rffi.LONG, end_ptr[0]) -
- rffi.cast(rffi.LONG, ll_input))
- raise ValueError("invalid input at position %d" % (offset,))
- return result
-
-def dtoa(value, mode=0, precision=0):
- builder = StringBuilder(20)
- with lltype.scoped_alloc(rffi.INTP.TO, 1) as decpt_ptr:
- with lltype.scoped_alloc(rffi.INTP.TO, 1) as sign_ptr:
- with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as end_ptr:
- output_ptr = dg_dtoa(value, mode, precision,
- decpt_ptr, sign_ptr, end_ptr)
- try:
- buflen = (rffi.cast(rffi.LONG, end_ptr[0]) -
- rffi.cast(rffi.LONG, output_ptr))
- intpart = rffi.cast(lltype.Signed, decpt_ptr[0])
- if intpart <= buflen:
- builder.append(rffi.charpsize2str(output_ptr, intpart))
- else:
- builder.append(rffi.charpsize2str(output_ptr, buflen))
- while buflen < intpart:
- builder.append('0')
- intpart -= 1
- builder.append('.')
- fracpart = buflen - intpart
- if fracpart > 0:
- ptr = rffi.ptradd(output_ptr, intpart)
- builder.append(rffi.charpsize2str(ptr, fracpart))
- finally:
- dg_freedtoa(output_ptr)
- return builder.build()
-
-def test_strtod():
- assert strtod("12345") == 12345.0
- assert strtod("1.1") == 1.1
- assert strtod("3.47") == 3.47
- raises(ValueError, strtod, "123A")
-
-def test_dtoa():
- assert dtoa(3.47) == "3.47"
- assert dtoa(1.1) == "1.1"
- assert dtoa(12.3577) == "12.3577"
- assert dtoa(10) == "10."
- assert dtoa(1e100) == "1" + "0" * 100 + "."
diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py
--- a/pypy/module/pypyjit/test/test_pypy_c.py
+++ b/pypy/module/pypyjit/test/test_pypy_c.py
@@ -150,6 +150,14 @@
_, self.sliced_entrybridge, _ = \
self.parse_rawloops(self.rawentrybridges)
+ from pypy.jit.tool.jitoutput import parse_prof
+ summaries = logparser.extract_category(log, 'jit-summary')
+ if len(summaries) > 0:
+ self.jit_summary = parse_prof(summaries[-1])
+ else:
+ self.jit_summary = None
+
+
def parse_rawloops(self, rawloops):
from pypy.jit.tool.oparser import parse
loops = [parse(part, no_namespace=True) for part in rawloops]
@@ -1437,7 +1445,6 @@
count_debug_merge_point=False)
def test_mod(self):
- py.test.skip('Results are correct, but traces 1902 times (on trunk too).')
avalues = ('a', 'b', 7, -42, 8)
bvalues = ['b'] + range(-10, 0) + range(1,10)
code = ''
@@ -1466,11 +1473,25 @@
%s
i += 1
return sa
- ''' % code, 0, ([a1, b1], 2000 * res1),
+ ''' % code, 150, ([a1, b1], 2000 * res1),
([a2, b2], 2000 * res2),
([a3, b3], 2000 * res3),
count_debug_merge_point=False)
+ def test_dont_trace_every_iteration(self):
+ self.run_source('''
+ def main(a, b):
+ i = sa = 0
+ while i < 200:
+ if a > 0: pass
+ if 1 < b < 2: pass
+ sa += a % b
+ i += 1
+ return sa
+ ''', 11, ([10, 20], 200 * (10 % 20)),
+ ([-10, -20], 200 * (-10 % -20)),
+ count_debug_merge_point=False)
+ assert self.jit_summary.tracing_no == 2
def test_id_compare_optimization(self):
# XXX: lower the instruction count, 35 is the old value.
self.run_source("""
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
@@ -19,7 +19,7 @@
from pypy.jit.metainterp.jitexc import JitException, get_llexception
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import specialize
-from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
+from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr, MissingLiveness
from pypy.jit.codewriter import heaptracker
from pypy.jit.metainterp.optimizeutil import RetraceLoop
@@ -819,8 +819,8 @@
self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc)
return clsbox
- @arguments("int")
- def opimpl_loop_header(self, jdindex):
+ @arguments("int", "orgpc")
+ def opimpl_loop_header(self, jdindex, orgpc):
self.metainterp.seen_loop_header_for_jdindex = jdindex
def verify_green_args(self, jitdriver_sd, varargs):
@@ -832,12 +832,16 @@
@arguments("orgpc", "int", "boxes3", "jitcode_position", "boxes3")
def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes,
jcposition, redboxes):
+ resumedescr = compile.ResumeAtPositionDescr()
+ self.capture_resumedata(resumedescr, orgpc)
+
any_operation = len(self.metainterp.history.operations) > 0
jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
self.verify_green_args(jitdriver_sd, greenboxes)
# xxx we may disable the following line in some context later
self.debug_merge_point(jitdriver_sd, 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:
return
@@ -848,6 +852,7 @@
"found a loop_header for a JitDriver that does not match "
"the following jit_merge_point's")
self.metainterp.seen_loop_header_for_jdindex = -1
+
#
if not self.metainterp.in_recursion:
assert jitdriver_sd is self.metainterp.jitdriver_sd
@@ -857,7 +862,7 @@
# much less expensive to blackhole out of.
saved_pc = self.pc
self.pc = orgpc
- self.metainterp.reached_loop_header(greenboxes, redboxes)
+ self.metainterp.reached_loop_header(greenboxes, redboxes, resumedescr)
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
@@ -1075,20 +1080,26 @@
resumedescr = compile.ResumeGuardDescr()
guard_op = metainterp.history.record(opnum, moreargs, None,
descr=resumedescr)
+ self.capture_resumedata(resumedescr, resumepc)
+ self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS)
+ # count
+ metainterp.attach_debug_info(guard_op)
+ return guard_op
+
+ def capture_resumedata(self, resumedescr, resumepc=-1):
+ metainterp = self.metainterp
virtualizable_boxes = None
if (metainterp.jitdriver_sd.virtualizable_info is not None or
metainterp.jitdriver_sd.greenfield_info is not None):
virtualizable_boxes = metainterp.virtualizable_boxes
saved_pc = self.pc
- if resumepc >= 0:
- self.pc = resumepc
- resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
- metainterp.virtualref_boxes, resumedescr)
- self.pc = saved_pc
- self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS)
- # count
- metainterp.attach_debug_info(guard_op)
- return guard_op
+ try:
+ if resumepc >= 0:
+ self.pc = resumepc
+ resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
+ metainterp.virtualref_boxes, resumedescr)
+ finally:
+ self.pc = saved_pc
def implement_guard_value(self, orgpc, box):
"""Promote the given Box into a Const. Note: be careful, it's a
@@ -1192,7 +1203,7 @@
self.execute_varargs(rop.CALL, allboxes, descr, False))
elif effect == effectinfo.EF_LOOPINVARIANT:
return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes,
- descr, True)
+ descr, False)
else:
return self.execute_varargs(rop.CALL, allboxes, descr, True)
@@ -1703,8 +1714,13 @@
self.current_merge_points = []
self.resumekey = key
self.seen_loop_header_for_jdindex = -1
- try:
- self.prepare_resume_from_failure(key.guard_opnum)
+ if isinstance(key, compile.ResumeAtPositionDescr):
+ self.seen_loop_header_for_jdindex = self.jitdriver_sd.index
+ dont_change_position = True
+ else:
+ dont_change_position = False
+ try:
+ self.prepare_resume_from_failure(key.guard_opnum, dont_change_position)
if self.resumekey_original_loop_token is None: # very rare case
raise SwitchToBlackhole(ABORT_BRIDGE)
self.interpret()
@@ -1734,7 +1750,7 @@
else:
duplicates[box] = None
- def reached_loop_header(self, greenboxes, redboxes):
+ def reached_loop_header(self, greenboxes, redboxes, resumedescr):
duplicates = {}
self.remove_consts_and_duplicates(redboxes, len(redboxes),
duplicates)
@@ -1789,9 +1805,9 @@
bridge_arg_boxes = self.retracing_loop_from.live_arg_boxes
self.compile_bridge_and_loop(original_boxes, \
live_arg_boxes, start,
- bridge_arg_boxes)
+ bridge_arg_boxes, resumedescr)
else:
- self.compile(original_boxes, live_arg_boxes, start)
+ self.compile(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')
@@ -1808,10 +1824,11 @@
history.set_future_values(self.cpu, residual_args)
return loop_token
- def prepare_resume_from_failure(self, opnum):
+ def prepare_resume_from_failure(self, opnum, dont_change_position=False):
frame = self.framestack[-1]
if opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now
- frame.pc = frame.jitcode.follow_jump(frame.pc)
+ if not dont_change_position:
+ frame.pc = frame.jitcode.follow_jump(frame.pc)
elif opnum == rop.GUARD_FALSE: # a goto_if_not that stops jumping
pass
elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS:
@@ -1854,14 +1871,14 @@
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):
+ def compile(self, original_boxes, live_arg_boxes, start, start_resumedescr):
num_green_args = self.jitdriver_sd.num_green_args
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)
+ greenkey, start, start_resumedescr)
if loop_token is not None: # raise if it *worked* correctly
self.set_compiled_merge_points(greenkey, old_loop_tokens)
raise GenerateMergePoint(live_arg_boxes, loop_token)
@@ -1887,7 +1904,7 @@
self.history.operations.pop() # remove the JUMP
def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
- bridge_arg_boxes):
+ bridge_arg_boxes, start_resumedescr):
num_green_args = self.jitdriver_sd.num_green_args
original_inputargs = self.history.inputargs
greenkey = original_boxes[:num_green_args]
@@ -1896,7 +1913,7 @@
self.history.inputargs = original_boxes[num_green_args:]
greenkey = original_boxes[:num_green_args]
self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
- loop_token = compile.compile_new_loop(self, [], greenkey, start)
+ loop_token = compile.compile_new_loop(self, [], greenkey, start, start_resumedescr)
self.history.operations.pop() # remove the JUMP
if loop_token is None:
return
diff --git a/pypy/jit/metainterp/simple_optimize.py b/pypy/jit/metainterp/simple_optimize.py
--- a/pypy/jit/metainterp/simple_optimize.py
+++ b/pypy/jit/metainterp/simple_optimize.py
@@ -47,7 +47,7 @@
jumpop.setdescr(loop.token)
return None
-def optimize_bridge(metainterp_sd, old_loops, loop):
+def optimize_bridge(metainterp_sd, old_loops, loop, inline_short_preamble):
optimize_loop(metainterp_sd, [], loop)
jumpop = loop.operations[-1]
if jumpop.getopnum() == rop.JUMP:
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -722,18 +722,19 @@
tr = Transformer()
tr.portal_jd = jd
oplist = tr.rewrite_operation(op)
- assert len(oplist) == 6
+ assert len(oplist) == 7
assert oplist[0].opname == '-live-'
assert oplist[1].opname == 'int_guard_value'
assert oplist[1].args == [v1]
assert oplist[2].opname == '-live-'
assert oplist[3].opname == 'int_guard_value'
assert oplist[3].args == [v2]
- assert oplist[4].opname == 'jit_merge_point'
- assert oplist[4].args[0].value == 42
- assert list(oplist[4].args[1]) == [v1, v2]
- assert list(oplist[4].args[4]) == [v3, v4]
- assert oplist[5].opname == '-live-'
+ assert oplist[4].opname == '-live-'
+ assert oplist[5].opname == 'jit_merge_point'
+ assert oplist[5].args[0].value == 42
+ assert list(oplist[5].args[1]) == [v1, v2]
+ assert list(oplist[5].args[4]) == [v3, v4]
+ assert oplist[6].opname == '-live-'
def test_getfield_gc():
S = lltype.GcStruct('S', ('x', lltype.Char))
diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py
--- a/pypy/jit/metainterp/test/test_compile.py
+++ b/pypy/jit/metainterp/test/test_compile.py
@@ -86,7 +86,7 @@
metainterp.history.inputargs = loop.inputargs[:]
#
loop_tokens = []
- loop_token = compile_new_loop(metainterp, loop_tokens, [], 0)
+ loop_token = compile_new_loop(metainterp, loop_tokens, [], 0, None)
assert loop_tokens == [loop_token]
assert loop_token.number == 1
assert staticdata.globaldata.loopnumbering == 2
@@ -102,7 +102,7 @@
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
#
- loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0)
+ loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0, None)
assert loop_token_2 is loop_token
assert loop_tokens == [loop_token]
assert len(cpu.seen) == 0
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -291,11 +291,12 @@
#__________________________________________________________
def timeval_from_double(d, timeval):
- timeval.c_tv_sec = int(d)
- timeval.c_tv_usec = int((d - int(d)) * 1000000)
+ rffi.setintfield(timeval, 'c_tv_sec', int(d))
+ rffi.setintfield(timeval, 'c_tv_usec', int((d - int(d)) * 1000000))
def double_from_timeval(tv):
- return tv.c_tv_sec + (tv.c_tv_usec / 1000000.0)
+ return rffi.getintfield(tv, 'c_tv_sec') + (
+ rffi.getintfield(tv, 'c_tv_usec') / 1000000.0)
def itimer_retval(space, val):
w_value = space.wrap(double_from_timeval(val.c_it_value))
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -9,7 +9,7 @@
from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
from pypy.jit.codewriter import heaptracker
from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise
-
+from pypy.jit.metainterp.compile import ResumeAtPositionDescr
def arguments(*argtypes, **kwds):
resulttype = kwds.pop('returns', None)
@@ -1210,13 +1210,14 @@
assert kind == 'v'
return lltype.nullptr(rclass.OBJECTPTR.TO)
- def _prepare_resume_from_failure(self, opnum):
+ def _prepare_resume_from_failure(self, opnum, dont_change_position=False):
from pypy.jit.metainterp.resoperation import rop
#
if opnum == rop.GUARD_TRUE:
# Produced directly by some goto_if_not_xxx() opcode that did not
# jump, but which must now jump. The pc is just after the opcode.
- self.position = self.jitcode.follow_jump(self.position)
+ if not dont_change_position:
+ self.position = self.jitcode.follow_jump(self.position)
#
elif opnum == rop.GUARD_FALSE:
# Produced directly by some goto_if_not_xxx() opcode that jumped,
@@ -1372,8 +1373,14 @@
jitdriver_sd,
resumedescr,
all_virtuals)
+ if isinstance(resumedescr, ResumeAtPositionDescr):
+ dont_change_position = True
+ else:
+ dont_change_position = False
+
current_exc = blackholeinterp._prepare_resume_from_failure(
- resumedescr.guard_opnum)
+ resumedescr.guard_opnum, dont_change_position)
+
try:
_run_forever(blackholeinterp, current_exc)
finally:
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1114,6 +1114,13 @@
self.wrap('read-write buffer expected'))
return buffer
+ def bufferstr_new_w(self, w_obj):
+ # Implement the "new buffer interface" (new in Python 2.7)
+ # returning an unwrapped string. It doesn't accept unicode
+ # strings
+ buffer = self.buffer_w(w_obj)
+ return buffer.as_str()
+
def bufferstr_w(self, w_obj):
# Directly returns an interp-level str. Note that if w_obj is a
# unicode string, this is different from str_w(buffer(w_obj)):
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -881,7 +881,9 @@
op1 = SpaceOperation('jit_merge_point', args, None)
op2 = SpaceOperation('-live-', [], None)
# ^^^ we need a -live- for the case of do_recursive_call()
- return ops + [op1, op2]
+ op3 = SpaceOperation('-live-', [], None)
+ # and one for inlined short preambles
+ return ops + [op3, op1, op2]
def handle_jit_marker__loop_header(self, op, jitdriver):
jd = self.callcontrol.jitdriver_sd_from_jitdriver(jitdriver)
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -436,9 +436,6 @@
self.newoperations.append(op)
def store_final_boxes_in_guard(self, op):
- ###pendingfields = self.heap_op_optimizer.force_lazy_setfields_for_guard()
- if op.getjumptarget():
- return op
descr = op.getdescr()
assert isinstance(descr, compile.ResumeGuardDescr)
modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -176,6 +176,15 @@
metainterp_sd.virtualref_info = self.vrefinfo
if hasattr(self, 'callinfocollection'):
metainterp_sd.callinfocollection = self.callinfocollection
+ class FakeDescr(compile.ResumeGuardDescr):
+ class rd_snapshot:
+ class prev:
+ prev = None
+ boxes = []
+ boxes = []
+ def clone_if_mutable(self):
+ return self
+ loop.preamble.start_resumedescr = FakeDescr()
optimize_loop_1(metainterp_sd, loop)
#
@@ -691,12 +700,16 @@
guard_nonnull(p0) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
setfield_gc(p0, 5, descr=valuedescr)
jump(p0)
"""
- self.optimize_loop(ops, expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_const_guard_value(self):
ops = """
@@ -2838,31 +2851,59 @@
def test_call_assembler_invalidates_caches(self):
ops = '''
- [p1, i1]
+ [p1, i1, i4]
setfield_gc(p1, i1, descr=valuedescr)
i3 = call_assembler(i1, descr=asmdescr)
setfield_gc(p1, i3, descr=valuedescr)
- jump(p1, i3)
+ jump(p1, i4, i3)
'''
- self.optimize_loop(ops, ops)
+ self.optimize_loop(ops, ops, ops)
+
+ def test_call_assembler_invalidates_heap_knowledge(self):
+ ops = '''
+ [p1, i1, i4]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call_assembler(i1, descr=asmdescr)
+ setfield_gc(p1, i1, descr=valuedescr)
+ jump(p1, i4, i3)
+ '''
+ self.optimize_loop(ops, ops, ops)
def test_call_pure_invalidates_caches(self):
# CALL_PURE should still force the setfield_gc() to occur before it
ops = '''
- [p1, i1]
+ [p1, i1, i4]
setfield_gc(p1, i1, descr=valuedescr)
i3 = call_pure(42, p1, descr=plaincalldescr)
setfield_gc(p1, i3, descr=valuedescr)
- jump(p1, i3)
+ jump(p1, i4, i3)
'''
expected = '''
- [p1, i1]
+ [p1, i1, i4]
setfield_gc(p1, i1, descr=valuedescr)
i3 = call(p1, descr=plaincalldescr)
setfield_gc(p1, i3, descr=valuedescr)
- jump(p1, i3)
+ jump(p1, i4, i3)
'''
- self.optimize_loop(ops, expected)
+ self.optimize_loop(ops, expected, expected)
+
+ def test_call_pure_invalidates_heap_knowledge(self):
+ # CALL_PURE should still force the setfield_gc() to occur before it
+ ops = '''
+ [p1, i1, i4]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call_pure(42, p1, descr=plaincalldescr)
+ setfield_gc(p1, i1, descr=valuedescr)
+ jump(p1, i4, i3)
+ '''
+ expected = '''
+ [p1, i1, i4]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call(p1, descr=plaincalldescr)
+ setfield_gc(p1, i1, descr=valuedescr)
+ jump(p1, i4, i3)
+ '''
+ self.optimize_loop(ops, expected, expected)
def test_call_pure_constant_folding(self):
# CALL_PURE is not marked as is_always_pure(), because it is wrong
@@ -3384,7 +3425,6 @@
"""
expected = """
[i0]
- i2 = int_add(i0, 10)
jump(i0)
"""
self.optimize_loop(ops, expected, preamble)
@@ -3675,10 +3715,9 @@
jump(p0, i22)
"""
expected = """
- [p0, i22, i1]
+ [p0, i22]
i331 = force_token()
- setfield_gc(p0, i1, descr=valuedescr)
- jump(p0, i22, i1)
+ jump(p0, i22)
"""
self.optimize_loop(ops, expected)
@@ -4184,7 +4223,6 @@
guard_no_overflow() []
i2 = int_gt(i1, 1)
guard_true(i2) []
- i3 = int_sub(1, i0)
jump(i0)
"""
expected = """
@@ -4519,16 +4557,11 @@
guard_true(i4) []
i5 = int_gt(i3, 2)
guard_true(i5) []
- jump(i0, i1, i22)
- """
- expected = """
- [i0, i1, i22]
- i3 = int_mul(i22, i1)
- i4 = int_lt(i3, 10)
- guard_true(i4) []
- i5 = int_gt(i3, 2)
- guard_true(i5) []
- jump(i0, i1, i22)
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ jump(i0, i1)
"""
self.optimize_loop(ops, expected, preamble)
@@ -4557,19 +4590,43 @@
guard_true(i4) []
i5 = int_ge(i3, 2)
guard_true(i5) []
- jump(i0, i1, i2)
- """
- expected = """
- [i0, i1, i2]
- i3 = int_sub(i2, i1)
- i4 = int_le(i3, 10)
- guard_true(i4) []
- i5 = int_ge(i3, 2)
- guard_true(i5) []
- jump(i0, i1, i2)
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ jump(i0, i1)
"""
self.optimize_loop(ops, expected, preamble)
+ def test_invariant_ovf(self):
+ ops = """
+ [i0, i1, i10, i11, i12]
+ i2 = int_add_ovf(i0, i1)
+ guard_no_overflow() []
+ i3 = int_sub_ovf(i0, i1)
+ guard_no_overflow() []
+ i4 = int_mul_ovf(i0, i1)
+ guard_no_overflow() []
+ i24 = int_mul_ovf(i10, i11)
+ guard_no_overflow() []
+ i23 = int_sub_ovf(i10, i11)
+ guard_no_overflow() []
+ i22 = int_add_ovf(i10, i11)
+ guard_no_overflow() []
+ jump(i0, i1, i2, i3, i4)
+ """
+ expected = """
+ [i0, i1, i10, i11, i12]
+ i24 = int_mul_ovf(i10, i11)
+ guard_no_overflow() []
+ i23 = int_sub_ovf(i10, i11)
+ guard_no_overflow() []
+ i22 = int_add_ovf(i10, i11)
+ guard_no_overflow() []
+ jump(i0, i1, i10, i11, i12)
+ """
+ self.optimize_loop(ops, expected, ops)
+
def test_value_proven_to_be_constant_after_two_iterations(self):
class FakeDescr(AbstractDescr):
def __init__(self, name):
@@ -4633,6 +4690,47 @@
"""
self.optimize_loop(ops, expected)
+ def test_let_getfield_kill_setfields(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=valuedescr)
+ setfield_gc(p0, p1, descr=valuedescr)
+ setfield_gc(p0, p1, descr=valuedescr)
+ setfield_gc(p0, p0, descr=valuedescr)
+ jump(p0)
+ """
+ preamble = """
+ [p0]
+ p1 = getfield_gc(p0, descr=valuedescr)
+ setfield_gc(p0, p0, descr=valuedescr)
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_let_getfield_kill_chained_setfields(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=valuedescr)
+ setfield_gc(p0, p0, descr=valuedescr)
+ setfield_gc(p0, p1, descr=valuedescr)
+ setfield_gc(p0, p1, descr=valuedescr)
+ jump(p0)
+ """
+ preamble = """
+ [p0]
+ p1 = getfield_gc(p0, descr=valuedescr)
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
def test_inputargs_added_by_forcing_jumpargs(self):
# FXIME: Can this occur?
ops = """
@@ -5282,6 +5380,7 @@
# more generally, supporting non-constant but virtual cases is
# not obvious, because of the exception UnicodeDecodeError that
# can be raised by ll_str2unicode()
+
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_basic.py
--- a/pypy/jit/metainterp/test/test_basic.py
+++ b/pypy/jit/metainterp/test/test_basic.py
@@ -1843,6 +1843,47 @@
'int_add': 1, 'int_mul': 1, 'int_sub': 2,
'int_gt': 2, 'jump': 2})
+ def test_multiple_specialied_versions_array(self):
+ myjitdriver = JitDriver(greens = [], reds = ['idx', 'y', 'x', 'res',
+ 'array'])
+ class Base:
+ def __init__(self, val):
+ self.val = val
+ class A(Base):
+ def binop(self, other):
+ return A(self.val + other.val)
+ class B(Base):
+ def binop(self, other):
+ return B(self.val - other.val)
+ def f(x, y):
+ res = x
+ array = [1, 2, 3]
+ array[1] = 7
+ idx = 0
+ while y > 0:
+ myjitdriver.can_enter_jit(idx=idx, y=y, x=x, res=res,
+ array=array)
+ myjitdriver.jit_merge_point(idx=idx, y=y, x=x, res=res,
+ array=array)
+ res = res.binop(x)
+ res.val += array[idx] + array[1]
+ if y < 7:
+ idx = 2
+ y -= 1
+ return res
+ def g(x, y):
+ a1 = f(A(x), y)
+ a2 = f(A(x), y)
+ b1 = f(B(x), y)
+ b2 = f(B(x), y)
+ assert a1.val == a2.val
+ assert b1.val == b2.val
+ return a1.val + b1.val
+ res = self.meta_interp(g, [6, 14])
+ assert res == g(6, 14)
+ self.check_loop_count(8)
+ self.check_loops(getarrayitem_gc=16, everywhere=True)
+
def test_multiple_specialied_versions_bridge(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
class Base:
@@ -1869,20 +1910,78 @@
def g(x, y):
a1 = f(A(x), y, A(x))
a2 = f(A(x), y, A(x))
+ assert a1.val == a2.val
b1 = f(B(x), y, B(x))
b2 = f(B(x), y, B(x))
+ assert b1.val == b2.val
c1 = f(B(x), y, A(x))
c2 = f(B(x), y, A(x))
+ assert c1.val == c2.val
d1 = f(A(x), y, B(x))
d2 = f(A(x), y, B(x))
- assert a1.val == a2.val
- assert b1.val == b2.val
- assert c1.val == c2.val
assert d1.val == d2.val
return a1.val + b1.val + c1.val + d1.val
res = self.meta_interp(g, [3, 14])
assert res == g(3, 14)
+ def test_failing_inlined_guard(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
+ class Base:
+ def __init__(self, val):
+ self.val = val
+ def getval(self):
+ return self.val
+ class A(Base):
+ def binop(self, other):
+ return A(self.getval() + other.getval())
+ class B(Base):
+ def binop(self, other):
+ return B(self.getval() * other.getval())
+ def f(x, y, z):
+ res = x
+ while y > 0:
+ myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
+ myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
+ res = res.binop(x)
+ y -= 1
+ if y < 8:
+ x = z
+ return res
+ def g(x, y):
+ c1 = f(A(x), y, B(x))
+ c2 = f(A(x), y, B(x))
+ assert c1.val == c2.val
+ return c1.val
+ res = self.meta_interp(g, [3, 16])
+ assert res == g(3, 16)
+
+ def test_inlined_guard_in_short_preamble(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
+ class A:
+ def __init__(self, val):
+ self.val = val
+ def getval(self):
+ return self.val
+ def binop(self, other):
+ return A(self.getval() + other.getval())
+ def f(x, y, z):
+ res = x
+ while y > 0:
+ myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
+ myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
+ res = res.binop(x)
+ y -= 1
+ if y < 7:
+ x = z
+ return res
+ def g(x, y):
+ a1 = f(A(x), y, A(x))
+ a2 = f(A(x), y, A(x))
+ assert a1.val == a2.val
+ return a1.val
+ res = self.meta_interp(g, [3, 14])
+ assert res == g(3, 14)
+
def test_specialied_bridge(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
class A:
@@ -1974,6 +2073,26 @@
self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
guard_false=2)
+ def test_dont_trace_every_iteration(self):
+ myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
+
+ def main(a, b):
+ i = sa = 0
+ #while i < 200:
+ while i < 200:
+ myjitdriver.can_enter_jit(a=a, b=b, i=i, sa=sa)
+ myjitdriver.jit_merge_point(a=a, b=b, i=i, sa=sa)
+ if a > 0: pass
+ if b < 2: pass
+ sa += a % b
+ i += 1
+ return sa
+ def g():
+ return main(10, 20) + main(-10, -20)
+ res = self.meta_interp(g, [])
+ assert res == g()
+ self.check_enter_count(3)
+
def test_current_trace_length(self):
myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
@dont_look_inside
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -198,7 +198,6 @@
class GuardResOp(ResOpWithDescr):
_fail_args = None
- _jump_target = None
def getfailargs(self):
return self._fail_args
@@ -206,22 +205,14 @@
def setfailargs(self, fail_args):
self._fail_args = fail_args
- def getjumptarget(self):
- return self._jump_target
-
- def setjumptarget(self, jump_target):
- self._jump_target = jump_target
-
def copy_and_change(self, opnum, args=None, result=None, descr=None):
newop = AbstractResOp.copy_and_change(self, opnum, args, result, descr)
newop.setfailargs(self.getfailargs())
- newop.setjumptarget(self.getjumptarget())
return newop
def clone(self):
newop = AbstractResOp.clone(self)
newop.setfailargs(self.getfailargs())
- newop.setjumptarget(self.getjumptarget())
return newop
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
@@ -6,17 +6,19 @@
from pypy.jit.metainterp.optimizeopt.string import OptString
from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble
-def optimize_loop_1(metainterp_sd, loop, unroll=True):
+def optimize_loop_1(metainterp_sd, loop, unroll=True, inline_short_preamble=True):
"""Optimize loop.operations to remove internal overheadish operations.
"""
opt_str = OptString()
- optimizations = [OptInlineShortPreamble(),
- OptIntBounds(),
+ optimizations = [OptIntBounds(),
OptRewrite(),
OptVirtualize(),
opt_str,
OptHeap(),
]
+ if inline_short_preamble:
+ optimizations = [OptInlineShortPreamble()] + optimizations
+
if metainterp_sd.jit_ffi:
from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
optimizations = optimizations + [
@@ -31,6 +33,6 @@
optimizer = Optimizer(metainterp_sd, loop, optimizations)
optimizer.propagate_all_forward()
-def optimize_bridge_1(metainterp_sd, bridge):
+def optimize_bridge_1(metainterp_sd, bridge, inline_short_preamble=True):
"""The same, but for a bridge. """
- optimize_loop_1(metainterp_sd, bridge, False)
+ optimize_loop_1(metainterp_sd, bridge, False, inline_short_preamble)
More information about the Pypy-commit
mailing list