Author: Hakan Ardo <[email protected]>
Branch:
Changeset: r47152:9f54c3c0bb32
Date: 2011-09-07 21:12 +0200
http://bitbucket.org/pypy/pypy/changeset/9f54c3c0bb32/
Log: Merge jit-duplicated_short_boxes, which introduces 3 things:
1: ValueImporter. Instead of placing guards for the state of every
Value that survives from the preamble into the peeled loop in the
short preamble, only place guards for the Values that are actually
used during the optimization. This reduces the size of the short
preambles significanlty.
2: UnrollableOptimizer. The optimizer has become more complex to
support unrolling, which has made it slower. Some of this complexity
is not needed when compiling bridges and has been split out into a
UnrollableOptimizer subclass which is only used for compiling loops
when unroll is enabled.
3: A strategy for solving conflicts among the short boxes. Conflicts
araises in situations such as:
[i1, i2] i3 = int_add(i1, 1) i4 = int_mul(i3, 2) escape(i4)
jump(i1, i3)
Specializing the peeled loop to the state at the end of the preamble
would specialize it to situations when it's inputargs are of the
form [i1, i1+1]. We dont want that. Instead a new box, i5, is
introduced, represeting the second argument of the jump as well as
the second inputargument of the peeled loop. Prior to this branch it
was the other way around, a new box was introduced to represent
i1+1. That resulted in the loop invariant int_mul would not be moved
out of the loop. Instead a potential int_mul(i2, 2) would have been
removed.
The same kind of situation can occure when a setfield_is cahced. In
that case, the set of pure ops that's optimized out would be quite
random. This branch introduces a strict priority order:
- ops found in the original trace
- synthetic ops (setfields converted to getfields)
- inputargs
- potential ops that was never promoted to short_boxes This makes the
effect of the optimizations less random and should always remove
loop invariant ops. Non loop invariant cases can still benefit from
unrolling but in exactly what situations has become more
complicated.
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py
b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -37,6 +37,12 @@
self.force_lazy_setfield(optheap)
assert not self.possible_aliasing(optheap, structvalue)
cached_fieldvalue = self._cached_fields.get(structvalue, None)
+
+ # Hack to ensure constants are imported from the preamble
+ if cached_fieldvalue and fieldvalue.is_constant():
+ optheap.optimizer.ensure_imported(cached_fieldvalue)
+ cached_fieldvalue = self._cached_fields.get(structvalue, None)
+
if cached_fieldvalue is not fieldvalue:
# common case: store the 'op' as lazy_setfield, and register
# myself in the optheap's _lazy_setfields_and_arrayitems list
@@ -132,9 +138,7 @@
result = newresult
getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)],
result, op.getdescr())
- getop = shortboxes.add_potential(getop)
- self._cached_fields_getfield_op[structvalue] = getop
- self._cached_fields[structvalue] =
optimizer.getvalue(result)
+ shortboxes.add_potential(getop, synthetic=True)
elif op.result is not None:
shortboxes.add_potential(op)
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
@@ -10,6 +10,7 @@
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.tool.pairtype import extendabletype
from pypy.rlib.debug import debug_start, debug_stop, debug_print
+from pypy.rlib.objectmodel import specialize
LEVEL_UNKNOWN = '\x00'
LEVEL_NONNULL = '\x01'
@@ -25,6 +26,9 @@
self.descr = descr
self.bound = bound
+ def clone(self):
+ return LenBound(self.mode, self.descr, self.bound.clone())
+
class OptValue(object):
__metaclass__ = extendabletype
_attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound',
'lenbound')
@@ -88,8 +92,27 @@
assert False
guards.append(op)
self.lenbound.bound.make_guards(lenbox, guards)
+ return guards
- return guards
+ def import_from(self, other, optimizer):
+ assert self.level <= LEVEL_NONNULL
+ if other.level == LEVEL_CONSTANT:
+ self.make_constant(other.get_key_box())
+ optimizer.turned_constant(self)
+ elif other.level == LEVEL_KNOWNCLASS:
+ self.make_constant_class(other.known_class, -1)
+ else:
+ if other.level == LEVEL_NONNULL:
+ self.ensure_nonnull()
+ self.intbound.intersect(other.intbound)
+ if other.lenbound:
+ if self.lenbound:
+ assert other.lenbound.mode == self.lenbound.mode
+ assert other.lenbound.descr == self.lenbound.descr
+ self.lenbound.bound.intersect(other.lenbound.bound)
+ else:
+ self.lenbound = other.lenbound.clone()
+
def force_box(self):
return self.box
@@ -308,7 +331,6 @@
self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd)
self.bool_boxes = {}
self.pure_operations = args_dict()
- self.emitted_pure_operations = {}
self.producer = {}
self.pendingfields = []
self.posponedop = None
@@ -316,12 +338,11 @@
self.quasi_immutable_deps = None
self.opaque_pointers = {}
self.newoperations = []
- self.emitting_dissabled = False
- self.emitted_guards = 0
if loop is not None:
self.call_pure_results = loop.call_pure_results
self.set_optimizations(optimizations)
+ self.setup()
def set_optimizations(self, optimizations):
if optimizations:
@@ -348,23 +369,18 @@
assert self.posponedop is None
def new(self):
+ new = Optimizer(self.metainterp_sd, self.loop)
+ return self._new(new)
+
+ def _new(self, new):
assert self.posponedop is None
- new = Optimizer(self.metainterp_sd, self.loop)
optimizations = [o.new() for o in self.optimizations]
new.set_optimizations(optimizations)
new.quasi_immutable_deps = self.quasi_immutable_deps
return new
def produce_potential_short_preamble_ops(self, sb):
- for op in self.emitted_pure_operations:
- if op.getopnum() == rop.GETARRAYITEM_GC_PURE or \
- op.getopnum() == rop.STRGETITEM or \
- op.getopnum() == rop.UNICODEGETITEM:
- if not self.getvalue(op.getarg(1)).is_constant():
- continue
- sb.add_potential(op)
- for opt in self.optimizations:
- opt.produce_potential_short_preamble_ops(sb)
+ raise NotImplementedError('This is implemented in
unroll.UnrollableOptimizer')
def turned_constant(self, value):
for o in self.optimizations:
@@ -386,19 +402,26 @@
else:
return box
+ @specialize.argtype(0)
def getvalue(self, box):
box = self.getinterned(box)
try:
value = self.values[box]
except KeyError:
value = self.values[box] = OptValue(box)
+ self.ensure_imported(value)
return value
+ def ensure_imported(self, value):
+ pass
+
+ @specialize.argtype(0)
def get_constant_box(self, box):
if isinstance(box, Const):
return box
try:
value = self.values[box]
+ self.ensure_imported(value)
except KeyError:
return None
if value.is_constant():
@@ -481,18 +504,22 @@
def emit_operation(self, op):
if op.returns_bool_result():
self.bool_boxes[self.getvalue(op.result)] = None
- if self.emitting_dissabled:
- return
+ self._emit_operation(op)
+ @specialize.argtype(0)
+ def _emit_operation(self, op):
for i in range(op.numargs()):
arg = op.getarg(i)
- if arg in self.values:
- box = self.values[arg].force_box()
- op.setarg(i, box)
+ try:
+ value = self.values[arg]
+ except KeyError:
+ pass
+ else:
+ self.ensure_imported(value)
+ op.setarg(i, value.force_box())
self.metainterp_sd.profiler.count(jitprof.OPT_OPS)
if op.is_guard():
self.metainterp_sd.profiler.count(jitprof.OPT_GUARDS)
- self.emitted_guards += 1 # FIXME: can we reuse above counter?
op = self.store_final_boxes_in_guard(op)
elif op.can_raise():
self.exception_might_have_happened = True
@@ -544,6 +571,7 @@
args[n+1] = op.getdescr()
return args
+ @specialize.argtype(0)
def optimize_default(self, op):
canfold = op.is_always_pure()
if op.is_ovf():
@@ -579,13 +607,16 @@
return
else:
self.pure_operations[args] = op
- self.emitted_pure_operations[op] = True
+ self.remember_emitting_pure(op)
# otherwise, the operation remains
self.emit_operation(op)
if nextop:
self.emit_operation(nextop)
+ def remember_emitting_pure(self, op):
+ pass
+
def constant_fold(self, op):
argboxes = [self.get_constant_box(op.getarg(i))
for i in range(op.numargs())]
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -472,7 +472,13 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, expected, preamble)
+ short = """
+ [i0]
+ i1 = int_is_true(i0)
+ guard_value(i1, 1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble, expected_short=short)
def test_bound_int_is_true(self):
ops = """
@@ -6997,6 +7003,26 @@
"""
self.optimize_loop(ops, expected)
+ def test_cached_pure_func_of_equal_fields(self):
+ ops = """
+ [p5, p6]
+ i10 = getfield_gc(p5, descr=valuedescr)
+ i11 = getfield_gc(p6, descr=nextdescr)
+ i12 = int_add(i10, 7)
+ i13 = int_add(i11, 7)
+ call(i12, i13, descr=nonwritedescr)
+ setfield_gc(p6, i10, descr=nextdescr)
+ jump(p5, p6)
+ """
+ expected = """
+ [p5, p6, i14, i12, i10]
+ i13 = int_add(i14, 7)
+ call(i12, i13, descr=nonwritedescr)
+ setfield_gc(p6, i10, descr=nextdescr)
+ jump(p5, p6, i10, i12, i10)
+ """
+ self.optimize_loop(ops, expected)
+
def test_forced_counter(self):
# XXX: VIRTUALHEAP (see above)
py.test.skip("would be fixed by make heap optimizer aware of virtual
setfields")
@@ -7086,8 +7112,84 @@
"""
self.optimize_loop(ops, expected)
+ def test_import_constants_when_folding_pure_operations(self):
+ ops = """
+ [p0]
+ f1 = getfield_gc(p0, descr=valuedescr)
+ f2 = float_abs(f1)
+ call(7.0, descr=nonwritedescr)
+ setfield_gc(p0, -7.0, descr=valuedescr)
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ call(7.0, descr=nonwritedescr)
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_exploding_duplicatipon(self):
+ ops = """
+ [i1, i2]
+ i3 = int_add(i1, i1)
+ i4 = int_add(i3, i3)
+ i5 = int_add(i4, i4)
+ i6 = int_add(i5, i5)
+ call(i6, descr=nonwritedescr)
+ jump(i1, i3)
+ """
+ expected = """
+ [i1, i2, i6, i3]
+ call(i6, descr=nonwritedescr)
+ jump(i1, i3, i6, i3)
+ """
+ short = """
+ [i1, i2]
+ i3 = int_add(i1, i1)
+ i4 = int_add(i3, i3)
+ i5 = int_add(i4, i4)
+ i6 = int_add(i5, i5)
+ jump(i1, i2, i6, i3)
+ """
+ self.optimize_loop(ops, expected, expected_short=short)
+
+ def test_prioritize_getfield1(self):
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ setfield_gc(p2, i1, descr=nextdescr)
+ i2 = int_neg(i1)
+ call(i2, descr=nonwritedescr)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2, i2, i1]
+ call(i2, descr=nonwritedescr)
+ setfield_gc(p2, i1, descr=nextdescr)
+ jump(p1, p2, i2, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_prioritize_getfield2(self):
+ # Same as previous, but with descrs intercahnged which means
+ # that the getfield is discovered first when looking for
+ # potential short boxes during tests
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=nextdescr)
+ setfield_gc(p2, i1, descr=valuedescr)
+ i2 = int_neg(i1)
+ call(i2, descr=nonwritedescr)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2, i2, i1]
+ call(i2, descr=nonwritedescr)
+ setfield_gc(p2, i1, descr=valuedescr)
+ jump(p1, p2, i2, i1)
+ """
+ self.optimize_loop(ops, expected)
-
class TestLLtype(OptimizeOptTest, LLtypeMixin):
pass
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
@@ -70,6 +70,47 @@
self.snapshot_map[snapshot] = new_snapshot
return new_snapshot
+class UnrollableOptimizer(Optimizer):
+ def setup(self):
+ self.importable_values = {}
+ self.emitting_dissabled = False
+ self.emitted_guards = 0
+ self.emitted_pure_operations = {}
+
+ def ensure_imported(self, value):
+ if not self.emitting_dissabled and value in self.importable_values:
+ imp = self.importable_values[value]
+ del self.importable_values[value]
+ imp.import_value(value)
+
+ def emit_operation(self, op):
+ if op.returns_bool_result():
+ self.bool_boxes[self.getvalue(op.result)] = None
+ if self.emitting_dissabled:
+ return
+ if op.is_guard():
+ self.emitted_guards += 1 # FIXME: can we use counter in
self._emit_operation?
+ self._emit_operation(op)
+
+ def new(self):
+ new = UnrollableOptimizer(self.metainterp_sd, self.loop)
+ return self._new(new)
+
+ def remember_emitting_pure(self, op):
+ self.emitted_pure_operations[op] = True
+
+ def produce_potential_short_preamble_ops(self, sb):
+ for op in self.emitted_pure_operations:
+ if op.getopnum() == rop.GETARRAYITEM_GC_PURE or \
+ op.getopnum() == rop.STRGETITEM or \
+ op.getopnum() == rop.UNICODEGETITEM:
+ if not self.getvalue(op.getarg(1)).is_constant():
+ continue
+ sb.add_potential(op)
+ for opt in self.optimizations:
+ opt.produce_potential_short_preamble_ops(sb)
+
+
class UnrollOptimizer(Optimization):
"""Unroll the loop into two iterations. The first one will
@@ -77,7 +118,7 @@
distinction anymore)"""
def __init__(self, metainterp_sd, loop, optimizations):
- self.optimizer = Optimizer(metainterp_sd, loop, optimizations)
+ self.optimizer = UnrollableOptimizer(metainterp_sd, loop,
optimizations)
self.cloned_operations = []
for op in self.optimizer.loop.operations:
newop = op.clone()
@@ -150,6 +191,7 @@
args = ", ".join([logops.repr_of_arg(arg) for arg in
short_inputargs])
debug_print('short inputargs: ' + args)
self.short_boxes.debug_print(logops)
+
# Force virtuals amoung the jump_args of the preamble to get the
# operations needed to setup the proper state of those virtuals
@@ -161,8 +203,9 @@
if box in seen:
continue
seen[box] = True
- value = preamble_optimizer.getvalue(box)
- inputarg_setup_ops.extend(value.make_guards(box))
+ preamble_value = preamble_optimizer.getvalue(box)
+ value = self.optimizer.getvalue(box)
+ value.import_from(preamble_value, self.optimizer)
for box in short_inputargs:
if box in seen:
continue
@@ -181,23 +224,16 @@
for op in self.short_boxes.operations():
self.ensure_short_op_emitted(op, self.optimizer, seen)
if op and op.result:
- # The order of these guards is not important as
- # self.optimizer.emitting_dissabled is False
- value = preamble_optimizer.getvalue(op.result)
- for guard in value.make_guards(op.result):
- self.optimizer.send_extra_operation(guard)
+ preamble_value = preamble_optimizer.getvalue(op.result)
+ value = self.optimizer.getvalue(op.result)
+ imp = ValueImporter(self, preamble_value, op)
+ self.optimizer.importable_values[value] = imp
newresult =
self.optimizer.getvalue(op.result).get_key_box()
if newresult is not op.result:
self.short_boxes.alias(newresult, op.result)
self.optimizer.flush()
self.optimizer.emitting_dissabled = False
- # XXX Hack to prevent the arraylen/strlen/unicodelen ops generated
- # by value.make_guards() from ending up in pure_operations
- for key, op in self.optimizer.pure_operations.items():
- if not self.short_boxes.has_producer(op.result):
- del self.optimizer.pure_operations[key]
-
initial_inputargs_len = len(inputargs)
self.inliner = Inliner(loop.inputargs, jump_args)
@@ -276,16 +312,11 @@
short_jumpargs = inputargs[:]
- short = []
- short_seen = {}
+ short = self.short = []
+ short_seen = self.short_seen = {}
for box, const in self.constant_inputargs.items():
short_seen[box] = True
- for op in self.short_boxes.operations():
- if op is not None:
- if len(self.getvalue(op.result).make_guards(op.result)) > 0:
- self.add_op_to_short(op, short, short_seen, False, True)
-
# This loop is equivalent to the main optimization loop in
# Optimizer.propagate_all_forward
jumpop = None
@@ -380,7 +411,7 @@
if op.is_ovf():
guard = ResOperation(rop.GUARD_NO_OVERFLOW, [], None)
optimizer.send_extra_operation(guard)
-
+
def add_op_to_short(self, op, short, short_seen, emit=True,
guards_needed=False):
if op is None:
return None
@@ -536,6 +567,13 @@
loop_token.failed_states.append(virtual_state)
self.emit_operation(op)
+class ValueImporter(object):
+ def __init__(self, unroll, value, op):
+ self.unroll = unroll
+ self.preamble_value = value
+ self.op = op
-
-
+ def import_value(self, value):
+ value.import_from(self.preamble_value, self.unroll.optimizer)
+ self.unroll.add_op_to_short(self.op, self.unroll.short,
self.unroll.short_seen, False, True)
+
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py
b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -58,6 +58,9 @@
def _really_force(self):
raise NotImplementedError("abstract base")
+ def import_from(self, other, optimizer):
+ raise NotImplementedError("should not be called at this level")
+
def get_fielddescrlist_cache(cpu):
if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
result = descrlist_dict()
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
@@ -12,6 +12,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import debug_start, debug_stop, debug_print
from pypy.rlib.objectmodel import we_are_translated
+import os
class AbstractVirtualStateInfo(resume.AbstractVirtualInfo):
position = -1
@@ -461,8 +462,10 @@
class ShortBoxes(object):
def __init__(self, optimizer, surviving_boxes):
self.potential_ops = {}
- self.duplicates = {}
+ self.alternatives = {}
+ self.synthetic = {}
self.aliases = {}
+ self.rename = {}
self.optimizer = optimizer
for box in surviving_boxes:
self.potential_ops[box] = None
@@ -476,33 +479,81 @@
except BoxNotProducable:
pass
+ def prioritized_alternatives(self, box):
+ if box not in self.alternatives:
+ return [self.potential_ops[box]]
+ alts = self.alternatives[box]
+ hi, lo = 0, len(alts) - 1
+ while hi < lo:
+ if alts[lo] is None: # Inputarg, lowest priority
+ alts[lo], alts[-1] = alts[-1], alts[lo]
+ lo -= 1
+ elif alts[lo] not in self.synthetic: # Hi priority
+ alts[hi], alts[lo] = alts[lo], alts[hi]
+ hi += 1
+ else: # Low priority
+ lo -= 1
+ return alts
+
+ def renamed(self, box):
+ if box in self.rename:
+ return self.rename[box]
+ return box
+
+ def add_to_short(self, box, op):
+ if op:
+ op = op.clone()
+ for i in range(op.numargs()):
+ op.setarg(i, self.renamed(op.getarg(i)))
+ if box in self.short_boxes:
+ if op is None:
+ oldop = self.short_boxes[box].clone()
+ oldres = oldop.result
+ newbox = oldop.result = oldres.clonebox()
+ self.rename[box] = newbox
+ self.short_boxes[box] = None
+ self.short_boxes[newbox] = oldop
+ else:
+ newop = op.clone()
+ newbox = newop.result = op.result.clonebox()
+ self.short_boxes[newop.result] = newop
+ value = self.optimizer.getvalue(box)
+ self.optimizer.make_equal_to(newbox, value)
+ else:
+ self.short_boxes[box] = op
+
def produce_short_preamble_box(self, box):
if box in self.short_boxes:
return
if isinstance(box, Const):
return
if box in self.potential_ops:
- op = self.potential_ops[box]
- if op:
- for arg in op.getarglist():
- self.produce_short_preamble_box(arg)
- self.short_boxes[box] = op
+ ops = self.prioritized_alternatives(box)
+ produced_one = False
+ for op in ops:
+ try:
+ if op:
+ for arg in op.getarglist():
+ self.produce_short_preamble_box(arg)
+ except BoxNotProducable:
+ pass
+ else:
+ produced_one = True
+ self.add_to_short(box, op)
+ if not produced_one:
+ raise BoxNotProducable
else:
raise BoxNotProducable
- def add_potential(self, op):
+ def add_potential(self, op, synthetic=False):
if op.result not in self.potential_ops:
self.potential_ops[op.result] = op
- return op
- newop = op.clone()
- newop.result = op.result.clonebox()
- self.potential_ops[newop.result] = newop
- if op.result in self.duplicates:
- self.duplicates[op.result].append(newop.result)
else:
- self.duplicates[op.result] = [newop.result]
- self.optimizer.make_equal_to(newop.result,
self.optimizer.getvalue(op.result))
- return newop
+ if op.result not in self.alternatives:
+ self.alternatives[op.result] = [self.potential_ops[op.result]]
+ self.alternatives[op.result].append(op)
+ if synthetic:
+ self.synthetic[op] = True
def debug_print(self, logops):
debug_start('jit-short-boxes')
diff --git a/pypy/jit/metainterp/test/test_virtualstate.py
b/pypy/jit/metainterp/test/test_virtualstate.py
--- a/pypy/jit/metainterp/test/test_virtualstate.py
+++ b/pypy/jit/metainterp/test/test_virtualstate.py
@@ -2,7 +2,7 @@
import py
from pypy.jit.metainterp.optimize import InvalidLoop
from pypy.jit.metainterp.optimizeopt.virtualstate import VirtualStateInfo,
VStructStateInfo, \
- VArrayStateInfo, NotVirtualStateInfo, VirtualState
+ VArrayStateInfo, NotVirtualStateInfo, VirtualState, ShortBoxes
from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr, ConstInt,
ConstPtr
from pypy.rpython.lltypesystem import lltype
@@ -11,6 +11,7 @@
from pypy.jit.metainterp.history import TreeLoop, LoopToken
from pypy.jit.metainterp.optimizeopt.test.test_optimizeopt import FakeDescr,
FakeMetaInterpStaticData
from pypy.jit.metainterp.optimize import RetraceLoop
+from pypy.jit.metainterp.resoperation import ResOperation, rop
class TestBasic:
someptr1 = LLtypeMixin.myptr
@@ -129,6 +130,7 @@
info.fieldstate = [info]
assert info.generalization_of(info, {}, {})
+
class BaseTestGenerateGuards(BaseTest):
def guards(self, info1, info2, box, expected):
info1.position = info2.position = 0
@@ -910,3 +912,111 @@
class TestLLtypeBridges(BaseTestBridges, LLtypeMixin):
pass
+class FakeOptimizer:
+ def make_equal_to(*args):
+ pass
+ def getvalue(*args):
+ pass
+
+class TestShortBoxes:
+ p1 = BoxPtr()
+ p2 = BoxPtr()
+ p3 = BoxPtr()
+ p4 = BoxPtr()
+ i1 = BoxInt()
+ i2 = BoxInt()
+ i3 = BoxInt()
+ i4 = BoxInt()
+
+ def test_short_box_duplication_direct(self):
+ class Optimizer(FakeOptimizer):
+ def produce_potential_short_preamble_ops(_self, sb):
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p1],
self.i1))
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p2],
self.i1))
+ sb = ShortBoxes(Optimizer(), [self.p1, self.p2])
+ assert len(sb.short_boxes) == 4
+ assert self.i1 in sb.short_boxes
+ assert sum([op.result is self.i1 for op in sb.short_boxes.values() if
op]) == 1
+
+ def test_dont_duplicate_potential_boxes(self):
+ class Optimizer(FakeOptimizer):
+ def produce_potential_short_preamble_ops(_self, sb):
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p1],
self.i1))
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [BoxPtr()],
self.i1))
+ sb.add_potential(ResOperation(rop.INT_NEG, [self.i1], self.i2))
+ sb.add_potential(ResOperation(rop.INT_ADD, [ConstInt(7),
self.i2],
+ self.i3))
+ sb = ShortBoxes(Optimizer(), [self.p1, self.p2])
+ assert len(sb.short_boxes) == 5
+
+ def test_prioritize1(self):
+ class Optimizer(FakeOptimizer):
+ def produce_potential_short_preamble_ops(_self, sb):
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p1],
self.i1))
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p2],
self.i1))
+ sb.add_potential(ResOperation(rop.INT_NEG, [self.i1], self.i2))
+ sb = ShortBoxes(Optimizer(), [self.p1, self.p2])
+ assert len(sb.short_boxes.values()) == 5
+ int_neg = [op for op in sb.short_boxes.values()
+ if op and op.getopnum() == rop.INT_NEG]
+ assert len(int_neg) == 1
+ int_neg = int_neg[0]
+ getfield = [op for op in sb.short_boxes.values()
+ if op and op.result == int_neg.getarg(0)]
+ assert len(getfield) == 1
+ assert getfield[0].getarg(0) in [self.p1, self.p2]
+
+ def test_prioritize1bis(self):
+ class Optimizer(FakeOptimizer):
+ def produce_potential_short_preamble_ops(_self, sb):
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p1],
self.i1),
+ synthetic=True)
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p2],
self.i1),
+ synthetic=True)
+ sb.add_potential(ResOperation(rop.INT_NEG, [self.i1], self.i2))
+ sb = ShortBoxes(Optimizer(), [self.p1, self.p2])
+ assert len(sb.short_boxes.values()) == 5
+ int_neg = [op for op in sb.short_boxes.values()
+ if op and op.getopnum() == rop.INT_NEG]
+ assert len(int_neg) == 1
+ int_neg = int_neg[0]
+ getfield = [op for op in sb.short_boxes.values()
+ if op and op.result == int_neg.getarg(0)]
+ assert len(getfield) == 1
+ assert getfield[0].getarg(0) in [self.p1, self.p2]
+
+ def test_prioritize2(self):
+ class Optimizer(FakeOptimizer):
+ def produce_potential_short_preamble_ops(_self, sb):
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p1],
self.i1),
+ synthetic=True)
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p2],
self.i1))
+ sb.add_potential(ResOperation(rop.INT_NEG, [self.i1], self.i2))
+ sb = ShortBoxes(Optimizer(), [self.p1, self.p2])
+ assert len(sb.short_boxes.values()) == 5
+ int_neg = [op for op in sb.short_boxes.values()
+ if op and op.getopnum() == rop.INT_NEG]
+ assert len(int_neg) == 1
+ int_neg = int_neg[0]
+ getfield = [op for op in sb.short_boxes.values()
+ if op and op.result == int_neg.getarg(0)]
+ assert len(getfield) == 1
+ assert getfield[0].getarg(0) == self.p2
+
+ def test_prioritize3(self):
+ class Optimizer(FakeOptimizer):
+ def produce_potential_short_preamble_ops(_self, sb):
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p1],
self.i1))
+ sb.add_potential(ResOperation(rop.GETFIELD_GC, [self.p2],
self.i1),
+ synthetic=True)
+ sb.add_potential(ResOperation(rop.INT_NEG, [self.i1], self.i2))
+ sb = ShortBoxes(Optimizer(), [self.p1, self.p2])
+ assert len(sb.short_boxes.values()) == 5
+ int_neg = [op for op in sb.short_boxes.values()
+ if op and op.getopnum() == rop.INT_NEG]
+ assert len(int_neg) == 1
+ int_neg = int_neg[0]
+ getfield = [op for op in sb.short_boxes.values()
+ if op and op.result == int_neg.getarg(0)]
+ assert len(getfield) == 1
+ assert getfield[0].getarg(0) == self.p1
diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py
--- a/pypy/jit/tl/pypyjit_demo.py
+++ b/pypy/jit/tl/pypyjit_demo.py
@@ -2,22 +2,16 @@
pypyjit.set_param(threshold=200)
-def main(a, b):
- i = sa = 0
- while i < 300:
- if a > 0: # Specialises the loop
- pass
- if b < 2 and b > 0:
- pass
- if (a >> b) >= 0:
- sa += 1
- if (a << b) > 2:
- sa += 10000
- i += 1
- return sa
+def f(n):
+ pairs = [(0.0, 1.0), (2.0, 3.0)] * n
+ mag = 0
+ for (x1, x2) in pairs:
+ dx = x1 - x2
+ mag += ((dx * dx ) ** (-1.5))
+ return n
try:
- print main(2, 1)
+ print f(301)
except Exception, e:
print "Exception: ", type(e)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -1,5 +1,5 @@
from __future__ import with_statement
-import sys
+import sys, os
import types
import subprocess
import py
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py
b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -92,6 +92,43 @@
""")
+ def test_cached_pure_func_of_equal_fields(self):
+ def main(n):
+ class A(object):
+ def __init__(self, val):
+ self.val1 = self.val2 = val
+ a = A(1)
+ b = A(1)
+ sa = 0
+ while n:
+ sa += 2*a.val1
+ sa += 2*b.val2
+ b.val2 = a.val1
+ n -= 1
+ return sa
+ #
+ log = self.run(main, [1000])
+ assert log.result == 4000
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i12 = int_is_true(i4)
+ guard_true(i12, descr=...)
+ guard_not_invalidated(descr=...)
+ i13 = int_add_ovf(i8, i9)
+ guard_no_overflow(descr=...)
+ i10p = getfield_gc_pure(p10, descr=...)
+ i10 = int_mul_ovf(2, i10p)
+ guard_no_overflow(descr=...)
+ i14 = int_add_ovf(i13, i10)
+ guard_no_overflow(descr=...)
+ setfield_gc(p7, p11, descr=...)
+ i17 = int_sub_ovf(i4, 1)
+ guard_no_overflow(descr=...)
+ --TICK--
+ jump(..., descr=...)
+ """)
+
+
def test_range_iter(self):
def main(n):
def g(n):
@@ -115,7 +152,6 @@
i21 = force_token()
setfield_gc(p4, i20, descr=<.*
.*W_AbstractSeqIterObject.inst_index .*>)
guard_not_invalidated(descr=...)
- i26 = int_sub(i9, 1)
i23 = int_lt(i18, 0)
guard_false(i23, descr=...)
i25 = int_ge(i18, i9)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit