[pypy-svn] pypy arm-backend-2: merge default
bivab
commits-noreply at bitbucket.org
Wed Jan 12 10:17:59 CET 2011
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r40620:fa0f17ad7944
Date: 2011-01-10 20:54 +0100
http://bitbucket.org/pypy/pypy/changeset/fa0f17ad7944/
Log: merge default
diff --git a/pypy/jit/metainterp/specnode.py b/pypy/jit/metainterp/specnode.py
deleted file mode 100644
--- a/pypy/jit/metainterp/specnode.py
+++ /dev/null
@@ -1,127 +0,0 @@
-from pypy.tool.pairtype import extendabletype
-from pypy.jit.metainterp.history import Const
-
-
-class SpecNode(object):
- __metaclass__ = extendabletype # extended in optimizefindnode.py
- __slots__ = ()
-
- def equals(self, other, ge): # 'ge' stands for greater-or-equal;
- raise NotImplementedError # if false, the default is 'equal'.
-
- def extract_runtime_data(self, cpu, valuebox, resultlist):
- raise NotImplementedError
-
-
-class NotSpecNode(SpecNode):
- __slots__ = ()
-
- def equals(self, other, ge):
- return isinstance(other, NotSpecNode) or ge
-
- def extract_runtime_data(self, cpu, valuebox, resultlist):
- resultlist.append(valuebox)
-
-
-prebuiltNotSpecNode = NotSpecNode()
-
-
-class ConstantSpecNode(SpecNode):
- def __init__(self, constbox):
- assert isinstance(constbox, Const)
- self.constbox = constbox
-
- def equals(self, other, ge):
- return isinstance(other, ConstantSpecNode) and \
- self.constbox.same_constant(other.constbox)
-
- def extract_runtime_data(self, cpu, valuebox, resultlist):
- pass
-
-
-class AbstractVirtualStructSpecNode(SpecNode):
- def __init__(self, fields):
- self.fields = fields # list: [(fieldofs, subspecnode)]
-
- def equal_fields(self, other, ge):
- if len(self.fields) != len(other.fields):
- return False
- for i in range(len(self.fields)):
- o1, s1 = self.fields[i]
- o2, s2 = other.fields[i]
- if not (o1 is o2 and s1.equals(s2, ge)):
- return False
- return True
-
- def extract_runtime_data(self, cpu, valuebox, resultlist):
- from pypy.jit.metainterp import executor, history, resoperation
- for ofs, subspecnode in self.fields:
- assert isinstance(ofs, history.AbstractDescr)
- fieldbox = executor.execute(cpu, None,
- resoperation.rop.GETFIELD_GC,
- ofs, valuebox)
- subspecnode.extract_runtime_data(cpu, fieldbox, resultlist)
-
-
-class VirtualInstanceSpecNode(AbstractVirtualStructSpecNode):
- def __init__(self, known_class, fields):
- AbstractVirtualStructSpecNode.__init__(self, fields)
- assert isinstance(known_class, Const)
- self.known_class = known_class
-
- def equals(self, other, ge):
- if not (isinstance(other, VirtualInstanceSpecNode) and
- self.known_class.same_constant(other.known_class)):
- return False
- return self.equal_fields(other, ge)
-
-
-class VirtualArraySpecNode(SpecNode):
- def __init__(self, arraydescr, items):
- self.arraydescr = arraydescr
- self.items = items # list of subspecnodes
-
- def equals(self, other, ge):
- if not (isinstance(other, VirtualArraySpecNode) and
- len(self.items) == len(other.items)):
- return False
- assert self.arraydescr == other.arraydescr
- for i in range(len(self.items)):
- s1 = self.items[i]
- s2 = other.items[i]
- if not s1.equals(s2, ge):
- return False
- return True
-
- def extract_runtime_data(self, cpu, valuebox, resultlist):
- from pypy.jit.metainterp import executor, history, resoperation
- for i in range(len(self.items)):
- itembox = executor.execute(cpu, None,
- resoperation.rop.GETARRAYITEM_GC,
- self.arraydescr,
- valuebox, history.ConstInt(i))
- subspecnode = self.items[i]
- subspecnode.extract_runtime_data(cpu, itembox, resultlist)
-
-
-class VirtualStructSpecNode(AbstractVirtualStructSpecNode):
- def __init__(self, typedescr, fields):
- AbstractVirtualStructSpecNode.__init__(self, fields)
- self.typedescr = typedescr
-
- def equals(self, other, ge):
- if not isinstance(other, VirtualStructSpecNode):
- return False
- assert self.typedescr == other.typedescr
- return self.equal_fields(other, ge)
-
-
-def equals_specnodes(specnodes1, specnodes2, ge=False):
- assert len(specnodes1) == len(specnodes2)
- for i in range(len(specnodes1)):
- if not specnodes1[i].equals(specnodes2[i], ge):
- return False
- return True
-
-def more_general_specnodes(specnodes1, specnodes2):
- return equals_specnodes(specnodes1, specnodes2, ge=True)
diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py
--- a/pypy/jit/metainterp/optimizeopt/string.py
+++ b/pypy/jit/metainterp/optimizeopt/string.py
@@ -162,6 +162,17 @@
for value in self._chars:
value.get_args_for_fail(modifier)
+ def FIXME_enum_forced_boxes(self, boxes, already_seen):
+ key = self.get_key_box()
+ if key in already_seen:
+ return
+ already_seen[key] = None
+ if self.box is None:
+ for box in self._chars:
+ box.enum_forced_boxes(boxes, already_seen)
+ else:
+ boxes.append(self.box)
+
def _make_virtual(self, modifier):
return modifier.make_vstrplain(self.mode is mode_unicode)
@@ -169,12 +180,22 @@
class VStringConcatValue(VAbstractStringValue):
"""The concatenation of two other strings."""
- def setup(self, left, right, lengthbox):
+ lengthbox = None # or the computed length
+
+ def setup(self, left, right):
self.left = left
self.right = right
- self.lengthbox = lengthbox
- def getstrlen(self, _, mode):
+ def getstrlen(self, newoperations, mode):
+ if self.lengthbox is None:
+ len1box = self.left.getstrlen(newoperations, mode)
+ if len1box is None:
+ return None
+ len2box = self.right.getstrlen(newoperations, mode)
+ if len2box is None:
+ return None
+ self.lengthbox = _int_add(newoperations, len1box, len2box)
+ # ^^^ may still be None, if newoperations is None
return self.lengthbox
@specialize.arg(1)
@@ -204,6 +225,18 @@
self.left.get_args_for_fail(modifier)
self.right.get_args_for_fail(modifier)
+ def FIXME_enum_forced_boxes(self, boxes, already_seen):
+ key = self.get_key_box()
+ if key in already_seen:
+ return
+ already_seen[key] = None
+ if self.box is None:
+ self.left.enum_forced_boxes(boxes, already_seen)
+ self.right.enum_forced_boxes(boxes, already_seen)
+ self.lengthbox = None
+ else:
+ boxes.append(self.box)
+
def _make_virtual(self, modifier):
return modifier.make_vstrconcat(self.mode is mode_unicode)
@@ -250,6 +283,18 @@
self.vstart.get_args_for_fail(modifier)
self.vlength.get_args_for_fail(modifier)
+ def FIXME_enum_forced_boxes(self, boxes, already_seen):
+ key = self.get_key_box()
+ if key in already_seen:
+ return
+ already_seen[key] = None
+ if self.box is None:
+ self.vstr.enum_forced_boxes(boxes, already_seen)
+ self.vstart.enum_forced_boxes(boxes, already_seen)
+ self.vlength.enum_forced_boxes(boxes, already_seen)
+ else:
+ boxes.append(self.box)
+
def _make_virtual(self, modifier):
return modifier.make_vstrslice(self.mode is mode_unicode)
@@ -288,6 +333,8 @@
return ConstInt(box1.value + box2.value)
elif isinstance(box2, ConstInt) and box2.value == 0:
return box1
+ if newoperations is None:
+ return None
resbox = BoxInt()
newoperations.append(ResOperation(rop.INT_ADD, [box1, box2], resbox))
return resbox
@@ -318,7 +365,12 @@
class OptString(optimizer.Optimization):
"Handling of strings and unicodes."
+ enabled = True
+ def reconstruct_for_next_iteration(self, optimizer, valuemap):
+ self.enabled = True
+ return self
+
def make_vstring_plain(self, box, source_op, mode):
vvalue = VStringPlainValue(self.optimizer, box, source_op, mode)
self.make_equal_to(box, vvalue)
@@ -447,11 +499,8 @@
vleft.ensure_nonnull()
vright.ensure_nonnull()
newoperations = self.optimizer.newoperations
- len1box = vleft.getstrlen(newoperations, mode)
- len2box = vright.getstrlen(newoperations, mode)
- lengthbox = _int_add(newoperations, len1box, len2box)
value = self.make_vstring_concat(op.result, op, mode)
- value.setup(vleft, vright, lengthbox)
+ value.setup(vleft, vright)
return True
def opt_call_stroruni_STR_SLICE(self, op, mode):
@@ -600,6 +649,10 @@
self.optimizer.newoperations.append(op)
def propagate_forward(self, op):
+ if not self.enabled:
+ self.emit_operation(op)
+ return
+
opnum = op.getopnum()
for value, func in optimize_ops:
if opnum == value:
@@ -608,6 +661,7 @@
else:
self.emit_operation(op)
+
optimize_ops = _findall(OptString, 'optimize_')
def _findall_call_oopspec():
diff --git a/pypy/jit/metainterp/test/test_loop_dummy.py b/pypy/jit/metainterp/test/test_loop_dummy.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_loop_dummy.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# xxx mostly pointless
-
-from pypy.jit.metainterp.test import test_loop, test_send
-from pypy.jit.metainterp.warmspot import ll_meta_interp
-from pypy.rlib.jit import OPTIMIZER_SIMPLE
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-
-class LoopDummyTest(test_send.SendTests):
- def meta_interp(self, func, args, **kwds):
- return ll_meta_interp(func, args, optimizer=OPTIMIZER_SIMPLE,
- CPUClass=self.CPUClass,
- type_system=self.type_system,
- **kwds)
-
- def check_loops(self, *args, **kwds):
- pass
-
- def check_loop_count(self, count):
- pass
-
- def check_jumps(self, maxcount):
- pass
-
-class TestLLtype(LoopDummyTest, LLJitMixin):
- pass
-
-class TestOOtype(LoopDummyTest, OOJitMixin):
- pass
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
@@ -309,6 +309,123 @@
found += 1
assert found == 1
+ def test_loop_invariant_mul1(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
+ def f(x, y):
+ res = 0
+ while y > 0:
+ myjitdriver.can_enter_jit(x=x, y=y, res=res)
+ myjitdriver.jit_merge_point(x=x, y=y, res=res)
+ res += x * x
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 7])
+ assert res == 252
+ self.check_loop_count(1)
+ self.check_loops({'guard_true': 1,
+ 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
+ 'jump': 1})
+
+ def test_loop_invariant_mul_ovf(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
+ def f(x, y):
+ res = 0
+ while y > 0:
+ myjitdriver.can_enter_jit(x=x, y=y, res=res)
+ myjitdriver.jit_merge_point(x=x, y=y, res=res)
+ b = y * 2
+ res += ovfcheck(x * x) + b
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 7])
+ assert res == 308
+ self.check_loop_count(1)
+ self.check_loops({'guard_true': 1,
+ 'int_add': 2, 'int_sub': 1, 'int_gt': 1,
+ 'int_mul': 1,
+ 'jump': 1})
+
+ def test_loop_invariant_mul_bridge1(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
+ def f(x, y):
+ res = 0
+ while y > 0:
+ myjitdriver.can_enter_jit(x=x, y=y, res=res)
+ myjitdriver.jit_merge_point(x=x, y=y, res=res)
+ res += x * x
+ if y<16:
+ x += 1
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 32])
+ assert res == 3427
+ self.check_loop_count(3)
+
+ def test_loop_invariant_mul_bridge_maintaining1(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
+ def f(x, y):
+ res = 0
+ while y > 0:
+ myjitdriver.can_enter_jit(x=x, y=y, res=res)
+ myjitdriver.jit_merge_point(x=x, y=y, res=res)
+ res += x * x
+ if y<16:
+ res += 1
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 32])
+ assert res == 1167
+ self.check_loop_count(3)
+ self.check_loops({'int_add': 2, 'int_lt': 1,
+ 'int_sub': 2, 'guard_false': 1,
+ 'jump': 2,
+ 'int_gt': 1, 'guard_true': 1, 'int_mul': 1})
+
+
+ def test_loop_invariant_mul_bridge_maintaining2(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
+ def f(x, y):
+ res = 0
+ while y > 0:
+ myjitdriver.can_enter_jit(x=x, y=y, res=res)
+ myjitdriver.jit_merge_point(x=x, y=y, res=res)
+ z = x * x
+ res += z
+ if y<16:
+ res += z
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 32])
+ assert res == 1692
+ self.check_loop_count(3)
+ self.check_loops({'int_add': 2, 'int_lt': 1,
+ 'int_sub': 2, 'guard_false': 1,
+ 'jump': 2,
+ 'int_gt': 1, 'guard_true': 1, 'int_mul': 1})
+
+ def test_loop_invariant_intbox(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
+ class I:
+ __slots__ = 'intval'
+ _immutable_ = True
+ def __init__(self, intval):
+ self.intval = intval
+ def f(i, y):
+ res = 0
+ x = I(i)
+ while y > 0:
+ myjitdriver.can_enter_jit(x=x, y=y, res=res)
+ myjitdriver.jit_merge_point(x=x, y=y, res=res)
+ res += x.intval * x.intval
+ y -= 1
+ return res
+ res = self.meta_interp(f, [6, 7])
+ assert res == 252
+ self.check_loop_count(1)
+ self.check_loops({'guard_true': 1,
+ 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
+ 'jump': 1})
+
def test_loops_are_transient(self):
import gc, weakref
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
@@ -336,7 +453,9 @@
assert res == f(6, 15)
gc.collect()
- assert not [wr for wr in wr_loops if wr()]
+ #assert not [wr for wr in wr_loops if wr()]
+ for loop in [wr for wr in wr_loops if wr()]:
+ assert loop().name == 'short preamble'
def test_string(self):
def f(n):
@@ -484,7 +603,7 @@
res = self.meta_interp(f, [21, 5])
assert res == -1
# the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=1)
+ self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0)
def test_constant_across_mp(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -857,10 +976,9 @@
self.meta_interp(f, [20], repeat=7)
self.check_tree_loop_count(2) # the loop and the entry path
# we get:
- # ENTER - compile the new loop
- # ENTER - compile the entry bridge
+ # ENTER - compile the new loop and the entry bridge
# ENTER - compile the leaving path
- self.check_enter_count(3)
+ self.check_enter_count(2)
def test_bridge_from_interpreter_2(self):
# one case for backend - computing of framesize on guard failure
@@ -1238,7 +1356,7 @@
res = self.meta_interp(f, [10, 3])
assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
- self.check_tree_loop_count(1)
+ self.check_tree_loop_count(2)
res = self.meta_interp(f, [10, 13])
assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
@@ -1343,7 +1461,8 @@
return x
res = self.meta_interp(f, [299], listops=True)
assert res == f(299)
- self.check_loops(guard_class=0, guard_value=3)
+ self.check_loops(guard_class=0, guard_value=3)
+ self.check_loops(guard_class=0, guard_value=6, everywhere=True)
def test_merge_guardnonnull_guardclass(self):
from pypy.rlib.objectmodel import instantiate
@@ -1373,6 +1492,9 @@
assert res == f(299)
self.check_loops(guard_class=0, guard_nonnull=0,
guard_nonnull_class=2, guard_isnull=1)
+ self.check_loops(guard_class=0, guard_nonnull=0,
+ guard_nonnull_class=4, guard_isnull=2,
+ everywhere=True)
def test_merge_guardnonnull_guardvalue(self):
from pypy.rlib.objectmodel import instantiate
@@ -1401,6 +1523,9 @@
assert res == f(299)
self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
guard_nonnull_class=0, guard_isnull=1)
+ self.check_loops(guard_class=0, guard_nonnull=0, guard_value=4,
+ guard_nonnull_class=0, guard_isnull=2,
+ everywhere=True)
def test_merge_guardnonnull_guardvalue_2(self):
from pypy.rlib.objectmodel import instantiate
@@ -1429,6 +1554,9 @@
assert res == f(299)
self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
guard_nonnull_class=0, guard_isnull=1)
+ self.check_loops(guard_class=0, guard_nonnull=0, guard_value=4,
+ guard_nonnull_class=0, guard_isnull=2,
+ everywhere=True)
def test_merge_guardnonnull_guardclass_guardvalue(self):
from pypy.rlib.objectmodel import instantiate
@@ -1460,6 +1588,9 @@
assert res == f(399)
self.check_loops(guard_class=0, guard_nonnull=0, guard_value=3,
guard_nonnull_class=0, guard_isnull=1)
+ self.check_loops(guard_class=0, guard_nonnull=0, guard_value=6,
+ guard_nonnull_class=0, guard_isnull=2,
+ everywhere=True)
def test_residual_call_doesnt_lose_info(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'l'])
@@ -1485,7 +1616,8 @@
y.v = g(y.v) - y.v/y.v + lc/l[0] - 1
return y.v
res = self.meta_interp(f, [20], listops=True)
- self.check_loops(getfield_gc=1, getarrayitem_gc=0)
+ self.check_loops(getfield_gc=0, getarrayitem_gc=0)
+ self.check_loops(getfield_gc=1, getarrayitem_gc=0, everywhere=True)
def test_guard_isnull_nonnull(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
@@ -1515,7 +1647,7 @@
assert res == 42
self.check_loops(guard_nonnull=1, guard_isnull=1)
- def test_loop_invariant(self):
+ def test_loop_invariant1(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
class A(object):
pass
@@ -1540,7 +1672,8 @@
return res
res = self.meta_interp(g, [21])
assert res == 3 * 21
- self.check_loops(call=1)
+ self.check_loops(call=0)
+ self.check_loops(call=1, everywhere=True)
def test_bug_optimizeopt_mutates_ops(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'const', 'a'])
@@ -1676,6 +1809,171 @@
assert res == 8
py.test.raises(AssertGreenFailed, self.interp_operations, f, [8, 0])
+ def test_multiple_specialied_versions1(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
+ 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
+ while y > 0:
+ myjitdriver.can_enter_jit(y=y, x=x, res=res)
+ myjitdriver.jit_merge_point(y=y, x=x, res=res)
+ res = res.binop(x)
+ 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, 7])
+ assert res == 6*8 + 6**8
+ self.check_loop_count(5)
+ self.check_loops({'guard_true': 2,
+ 'int_add': 1, 'int_mul': 1, 'int_sub': 2,
+ 'int_gt': 2, 'jump': 2})
+
+ def test_multiple_specialied_versions_bridge(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 < 7:
+ x = z
+ return res
+ def g(x, y):
+ a1 = f(A(x), y, A(x))
+ a2 = f(A(x), y, A(x))
+ b1 = f(B(x), y, B(x))
+ b2 = f(B(x), y, B(x))
+ c1 = f(B(x), y, A(x))
+ c2 = f(B(x), y, A(x))
+ 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_specialied_bridge(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
+ class A:
+ def __init__(self, val):
+ self.val = val
+ def binop(self, other):
+ return A(self.val + other.val)
+ def f(x, y):
+ res = A(0)
+ while y > 0:
+ myjitdriver.can_enter_jit(y=y, x=x, res=res)
+ myjitdriver.jit_merge_point(y=y, x=x, res=res)
+ res = res.binop(A(y))
+ if y<7:
+ res = x
+ y -= 1
+ return res
+ def g(x, y):
+ a1 = f(A(x), y)
+ a2 = f(A(x), y)
+ assert a1.val == a2.val
+ return a1.val
+ res = self.meta_interp(g, [6, 14])
+ assert res == g(6, 14)
+
+ def test_specialied_bridge_const(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'const', 'x', 'res'])
+ class A:
+ def __init__(self, val):
+ self.val = val
+ def binop(self, other):
+ return A(self.val + other.val)
+ def f(x, y):
+ res = A(0)
+ const = 7
+ while y > 0:
+ myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const)
+ myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const)
+ const = hint(const, promote=True)
+ res = res.binop(A(const))
+ if y<7:
+ res = x
+ y -= 1
+ return res
+ def g(x, y):
+ a1 = f(A(x), y)
+ a2 = f(A(x), y)
+ assert a1.val == a2.val
+ return a1.val
+ res = self.meta_interp(g, [6, 14])
+ assert res == g(6, 14)
+
+ def test_multiple_specialied_zigzag(self):
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
+ class Base:
+ def __init__(self, val):
+ self.val = val
+ class A(Base):
+ def binop(self, other):
+ return A(self.val + other.val)
+ def switch(self):
+ return B(self.val)
+ class B(Base):
+ def binop(self, other):
+ return B(self.val * other.val)
+ def switch(self):
+ return A(self.val)
+ def f(x, y):
+ res = x
+ while y > 0:
+ myjitdriver.can_enter_jit(y=y, x=x, res=res)
+ myjitdriver.jit_merge_point(y=y, x=x, res=res)
+ if y % 4 == 0:
+ res = res.switch()
+ res = res.binop(x)
+ 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, [3, 23])
+ assert res == 7068153
+ self.check_loop_count(6)
+ self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
+ guard_false=2)
+
def test_current_trace_length(self):
myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
@dont_look_inside
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
@@ -45,6 +45,26 @@
def get_key_box(self):
return self.box
+ def enum_forced_boxes(self, boxes, already_seen):
+ key = self.get_key_box()
+ if key not in already_seen:
+ boxes.append(self.force_box())
+ already_seen[self.get_key_box()] = None
+
+ def get_reconstructed(self, optimizer, valuemap):
+ if self in valuemap:
+ return valuemap[self]
+ new = self.reconstruct_for_next_iteration(optimizer)
+ valuemap[self] = new
+ self.reconstruct_childs(new, valuemap)
+ return new
+
+ def reconstruct_for_next_iteration(self, optimizer):
+ return self
+
+ def reconstruct_childs(self, new, valuemap):
+ pass
+
def get_args_for_fail(self, modifier):
pass
@@ -100,6 +120,12 @@
box = self.box
assert isinstance(box, Const)
return box.nonnull()
+ elif self.intbound:
+ if self.intbound.known_gt(IntBound(0, 0)) or \
+ self.intbound.known_lt(IntBound(0, 0)):
+ return True
+ else:
+ return False
else:
return False
@@ -142,12 +168,20 @@
oohelper.CVAL_NULLREF = ConstantValue(oohelper.CONST_NULL)
class Optimization(object):
+ next_optimization = None
+
def propagate_forward(self, op):
raise NotImplementedError
def emit_operation(self, op):
self.next_optimization.propagate_forward(op)
+ def test_emittable(self, op):
+ return self.is_emittable(op)
+
+ def is_emittable(self, op):
+ return self.next_optimization.test_emittable(op)
+
# FIXME: Move some of these here?
def getvalue(self, box):
return self.optimizer.getvalue(box)
@@ -180,18 +214,23 @@
op = ResOperation(opnum, args, result)
self.optimizer.pure_operations[self.optimizer.make_args_key(op)] = op
- def nextop(self):
- return self.optimizer.loop.operations[self.optimizer.i + 1]
+ def setup(self):
+ pass
- def skip_nextop(self):
- self.optimizer.i += 1
+ def force_at_end_of_preamble(self):
+ pass
- def setup(self, virtuals):
+ def turned_constant(self, value):
pass
+ def reconstruct_for_next_iteration(self, optimizer=None, valuemap=None):
+ #return self.__class__()
+ raise NotImplementedError
+
+
class Optimizer(Optimization):
- def __init__(self, metainterp_sd, loop, optimizations=None, virtuals=True):
+ def __init__(self, metainterp_sd, loop, optimizations=None):
self.metainterp_sd = metainterp_sd
self.cpu = metainterp_sd.cpu
self.loop = loop
@@ -203,7 +242,13 @@
self.pure_operations = args_dict()
self.producer = {}
self.pendingfields = []
+ self.posponedop = None
+ self.exception_might_have_happened = False
+ self.newoperations = []
+ self.set_optimizations(optimizations)
+
+ def set_optimizations(self, optimizations):
if optimizations:
self.first_optimization = optimizations[0]
for i in range(1, len(optimizations)):
@@ -211,9 +256,50 @@
optimizations[-1].next_optimization = self
for o in optimizations:
o.optimizer = self
- o.setup(virtuals)
+ o.setup()
else:
+ optimizations = []
self.first_optimization = self
+
+ self.optimizations = optimizations
+
+ def force_at_end_of_preamble(self):
+ self.resumedata_memo = resume.ResumeDataLoopMemo(self.metainterp_sd)
+ for o in self.optimizations:
+ o.force_at_end_of_preamble()
+
+ def reconstruct_for_next_iteration(self, optimizer=None, valuemap=None):
+ assert optimizer is None
+ assert valuemap is None
+ valuemap = {}
+ new = Optimizer(self.metainterp_sd, self.loop)
+ optimizations = [o.reconstruct_for_next_iteration(new, valuemap) for o in
+ self.optimizations]
+ new.set_optimizations(optimizations)
+
+ new.values = {}
+ for box, value in self.values.items():
+ new.values[box] = value.get_reconstructed(new, valuemap)
+ new.interned_refs = self.interned_refs
+ new.bool_boxes = {}
+ for value in new.bool_boxes.keys():
+ new.bool_boxes[value.get_reconstructed(new, valuemap)] = None
+
+ # FIXME: Move to rewrite.py
+ new.loop_invariant_results = {}
+ for key, value in self.loop_invariant_results.items():
+ new.loop_invariant_results[key] = \
+ value.get_reconstructed(new, valuemap)
+
+ new.pure_operations = self.pure_operations
+ new.producer = self.producer
+ assert self.posponedop is None
+
+ return new
+
+ def turned_constant(self, value):
+ for o in self.optimizations:
+ o.turned_constant(value)
def forget_numberings(self, virtualbox):
self.metainterp_sd.profiler.count(jitprof.OPT_FORCINGS)
@@ -252,9 +338,9 @@
return constbox
return None
- def make_equal_to(self, box, value):
+ def make_equal_to(self, box, value, replace=False):
assert isinstance(value, OptValue)
- assert box not in self.values
+ assert replace or box not in self.values
self.values[box] = value
def make_constant(self, box, constbox):
@@ -306,7 +392,6 @@
self.i = 0
while self.i < len(self.loop.operations):
op = self.loop.operations[self.i]
- #print "OP: %s" % op
self.first_optimization.propagate_forward(op)
self.i += 1
self.loop.operations = self.newoperations
@@ -327,7 +412,9 @@
self.optimize_default(op)
#print '\n'.join([str(o) for o in self.newoperations]) + '\n---\n'
-
+ def test_emittable(self, op):
+ return True
+
def emit_operation(self, op):
###self.heap_op_optimizer.emitting_operation(op)
self._emit_operation(op)
@@ -350,6 +437,8 @@
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)
@@ -396,10 +485,17 @@
def optimize_default(self, op):
canfold = op.is_always_pure()
- is_ovf = op.is_ovf()
- if is_ovf:
- nextop = self.loop.operations[self.i + 1]
+ if op.is_ovf():
+ self.posponedop = op
+ return
+ if self.posponedop:
+ nextop = op
+ op = self.posponedop
+ self.posponedop = None
canfold = nextop.getopnum() == rop.GUARD_NO_OVERFLOW
+ else:
+ nextop = None
+
if canfold:
for i in range(op.numargs()):
if self.get_constant_box(op.getarg(i)) is None:
@@ -410,9 +506,8 @@
for i in range(op.numargs())]
resbox = execute_nonspec(self.cpu, None,
op.getopnum(), argboxes, op.getdescr())
+ # FIXME: Don't we need to check for an overflow here?
self.make_constant(op.result, resbox.constbox())
- if is_ovf:
- self.i += 1 # skip next operation, it is the unneeded guard
return
# did we do the exact same operation already?
@@ -420,20 +515,22 @@
oldop = self.pure_operations.get(args, None)
if oldop is not None and oldop.getdescr() is op.getdescr():
assert oldop.getopnum() == op.getopnum()
- self.make_equal_to(op.result, self.getvalue(oldop.result))
- if is_ovf:
- self.i += 1 # skip next operation, it is the unneeded guard
+ self.make_equal_to(op.result, self.getvalue(oldop.result),
+ True)
return
else:
self.pure_operations[args] = op
# otherwise, the operation remains
self.emit_operation(op)
+ if nextop:
+ self.emit_operation(nextop)
- def optimize_GUARD_NO_OVERFLOW(self, op):
- # otherwise the default optimizer will clear fields, which is unwanted
- # in this case
- self.emit_operation(op)
+ #def optimize_GUARD_NO_OVERFLOW(self, op):
+ # # otherwise the default optimizer will clear fields, which is unwanted
+ # # in this case
+ # self.emit_operation(op)
+ # FIXME: Is this still needed?
def optimize_DEBUG_MERGE_POINT(self, op):
self.emit_operation(op)
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
@@ -4,17 +4,17 @@
from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize
from pypy.jit.metainterp.optimizeopt.heap import OptHeap
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, virtuals=True):
- """Optimize loop.operations to make it match the input of loop.specnodes
- and to remove internal overheadish operations. Note that loop.specnodes
- must be applicable to the loop; you will probably get an AssertionError
- if not.
+def optimize_loop_1(metainterp_sd, loop, unroll=True):
+ """Optimize loop.operations to remove internal overheadish operations.
"""
- optimizations = [OptIntBounds(),
+ opt_str = OptString()
+ optimizations = [OptInlineShortPreamble(),
+ OptIntBounds(),
OptRewrite(),
OptVirtualize(),
- OptString(),
+ opt_str,
OptHeap(),
]
if metainterp_sd.jit_ffi:
@@ -22,11 +22,15 @@
optimizations = optimizations + [
OptFfiCall(),
]
- optimizer = Optimizer(metainterp_sd, loop, optimizations, virtuals)
- optimizer.propagate_all_forward()
+
+ if unroll:
+ opt_str.enabled = False # FIXME: Workaround to disable string optimisation
+ # during preamble but to keep it during the loop
+ optimize_unroll(metainterp_sd, loop, optimizations)
+ else:
+ optimizer = Optimizer(metainterp_sd, loop, optimizations)
+ optimizer.propagate_all_forward()
def optimize_bridge_1(metainterp_sd, bridge):
- """The same, but for a bridge. The only difference is that we don't
- expect 'specnodes' on the bridge.
- """
+ """The same, but for a bridge. """
optimize_loop_1(metainterp_sd, bridge, False)
diff --git a/pypy/jit/metainterp/test/test_optimizefindnode.py b/pypy/jit/metainterp/test/test_optimizefindnode.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_optimizefindnode.py
+++ /dev/null
@@ -1,1199 +0,0 @@
-import py, random
-
-from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
-from pypy.rpython.ootypesystem import ootype
-from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
-
-from pypy.jit.backend.llgraph import runner
-from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr,
- Const, TreeLoop, BoxObj,
- ConstObj, AbstractDescr)
-from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder
-from pypy.jit.metainterp.optimizefindnode import BridgeSpecializationFinder
-from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop
-from pypy.jit.metainterp.specnode import NotSpecNode, prebuiltNotSpecNode
-from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
-from pypy.jit.metainterp.specnode import VirtualArraySpecNode
-from pypy.jit.metainterp.specnode import VirtualStructSpecNode
-from pypy.jit.metainterp.specnode import ConstantSpecNode
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int
-from pypy.jit.tool.oparser import parse
-
-def test_sort_descrs():
- class PseudoDescr(AbstractDescr):
- def __init__(self, n):
- self.n = n
- def sort_key(self):
- return self.n
- for i in range(17):
- lst = [PseudoDescr(j) for j in range(i)]
- lst2 = lst[:]
- random.shuffle(lst2)
- sort_descrs(lst2)
- assert lst2 == lst
-
-# ____________________________________________________________
-
-class LLtypeMixin(object):
- type_system = 'lltype'
-
- def get_class_of_box(self, box):
- return box.getref(rclass.OBJECTPTR).typeptr
-
- node_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
- node_vtable.name = rclass.alloc_array_name('node')
- node_vtable_adr = llmemory.cast_ptr_to_adr(node_vtable)
- node_vtable2 = lltype.malloc(OBJECT_VTABLE, immortal=True)
- node_vtable2.name = rclass.alloc_array_name('node2')
- node_vtable_adr2 = llmemory.cast_ptr_to_adr(node_vtable2)
- cpu = runner.LLtypeCPU(None)
-
- NODE = lltype.GcForwardReference()
- NODE.become(lltype.GcStruct('NODE', ('parent', OBJECT),
- ('value', lltype.Signed),
- ('floatval', lltype.Float),
- ('next', lltype.Ptr(NODE))))
- NODE2 = lltype.GcStruct('NODE2', ('parent', NODE),
- ('other', lltype.Ptr(NODE)))
- node = lltype.malloc(NODE)
- node.parent.typeptr = node_vtable
- nodebox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node))
- myptr = nodebox.value
- myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(NODE))
- nodebox2 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node))
- nodesize = cpu.sizeof(NODE)
- nodesize2 = cpu.sizeof(NODE2)
- valuedescr = cpu.fielddescrof(NODE, 'value')
- floatdescr = cpu.fielddescrof(NODE, 'floatval')
- nextdescr = cpu.fielddescrof(NODE, 'next')
- otherdescr = cpu.fielddescrof(NODE2, 'other')
-
- NODEOBJ = lltype.GcStruct('NODEOBJ', ('parent', OBJECT),
- ('ref', lltype.Ptr(OBJECT)))
- nodeobj = lltype.malloc(NODEOBJ)
- nodeobjvalue = lltype.cast_opaque_ptr(llmemory.GCREF, nodeobj)
- refdescr = cpu.fielddescrof(NODEOBJ, 'ref')
-
- arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed))
- floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float))
-
- # a GcStruct not inheriting from OBJECT
- S = lltype.GcStruct('TUPLE', ('a', lltype.Signed), ('b', lltype.Ptr(NODE)))
- ssize = cpu.sizeof(S)
- adescr = cpu.fielddescrof(S, 'a')
- bdescr = cpu.fielddescrof(S, 'b')
- sbox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S)))
- arraydescr2 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(S)))
-
- T = lltype.GcStruct('TUPLE',
- ('c', lltype.Signed),
- ('d', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE)))))
- tsize = cpu.sizeof(T)
- cdescr = cpu.fielddescrof(T, 'c')
- ddescr = cpu.fielddescrof(T, 'd')
- arraydescr3 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(NODE)))
-
- U = lltype.GcStruct('U',
- ('parent', OBJECT),
- ('one', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE)))))
- u_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
- u_vtable_adr = llmemory.cast_ptr_to_adr(u_vtable)
- usize = cpu.sizeof(U)
- onedescr = cpu.fielddescrof(U, 'one')
-
- FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
- plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
- nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], []))
- writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [adescr], []))
- writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [adescr], [arraydescr]))
- readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([adescr], [], []))
- mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([nextdescr], [], [],
- EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE))
- arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY))
-
- for _name, _os in [
- ('strconcatdescr', 'OS_STR_CONCAT'),
- ('strslicedescr', 'OS_STR_SLICE'),
- ('strequaldescr', 'OS_STR_EQUAL'),
- ('streq_slice_checknull_descr', 'OS_STREQ_SLICE_CHECKNULL'),
- ('streq_slice_nonnull_descr', 'OS_STREQ_SLICE_NONNULL'),
- ('streq_slice_char_descr', 'OS_STREQ_SLICE_CHAR'),
- ('streq_nonnull_descr', 'OS_STREQ_NONNULL'),
- ('streq_nonnull_char_descr', 'OS_STREQ_NONNULL_CHAR'),
- ('streq_checknull_char_descr', 'OS_STREQ_CHECKNULL_CHAR'),
- ('streq_lengthok_descr', 'OS_STREQ_LENGTHOK'),
- ]:
- _oopspecindex = getattr(EffectInfo, _os)
- locals()[_name] = \
- cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], oopspecindex=_oopspecindex))
- #
- _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI'))
- locals()[_name.replace('str', 'unicode')] = \
- cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], oopspecindex=_oopspecindex))
-
- s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE))
- #
-
- class LoopToken(AbstractDescr):
- pass
- asmdescr = LoopToken() # it can be whatever, it's not a descr though
-
- from pypy.jit.metainterp.virtualref import VirtualRefInfo
- class FakeWarmRunnerDesc:
- pass
- FakeWarmRunnerDesc.cpu = cpu
- vrefinfo = VirtualRefInfo(FakeWarmRunnerDesc)
- virtualtokendescr = vrefinfo.descr_virtual_token
- virtualrefindexdescr = vrefinfo.descr_virtualref_index
- virtualforceddescr = vrefinfo.descr_forced
- jit_virtual_ref_vtable = vrefinfo.jit_virtual_ref_vtable
- jvr_vtable_adr = llmemory.cast_ptr_to_adr(jit_virtual_ref_vtable)
-
- register_known_gctype(cpu, node_vtable, NODE)
- register_known_gctype(cpu, node_vtable2, NODE2)
- register_known_gctype(cpu, u_vtable, U)
- register_known_gctype(cpu, jit_virtual_ref_vtable,vrefinfo.JIT_VIRTUAL_REF)
-
- namespace = locals()
-
-class OOtypeMixin_xxx_disabled(object):
- type_system = 'ootype'
-
-## def get_class_of_box(self, box):
-## root = box.getref(ootype.ROOT)
-## return ootype.classof(root)
-
-## cpu = runner.OOtypeCPU(None)
-## NODE = ootype.Instance('NODE', ootype.ROOT, {})
-## NODE._add_fields({'value': ootype.Signed,
-## 'floatval' : ootype.Float,
-## 'next': NODE})
-## NODE2 = ootype.Instance('NODE2', NODE, {'other': NODE})
-
-## node_vtable = ootype.runtimeClass(NODE)
-## node_vtable_adr = ootype.cast_to_object(node_vtable)
-## node_vtable2 = ootype.runtimeClass(NODE2)
-## node_vtable_adr2 = ootype.cast_to_object(node_vtable2)
-
-## node = ootype.new(NODE)
-## nodebox = BoxObj(ootype.cast_to_object(node))
-## myptr = nodebox.value
-## myptr2 = ootype.cast_to_object(ootype.new(NODE))
-## nodebox2 = BoxObj(ootype.cast_to_object(node))
-## valuedescr = cpu.fielddescrof(NODE, 'value')
-## floatdescr = cpu.fielddescrof(NODE, 'floatval')
-## nextdescr = cpu.fielddescrof(NODE, 'next')
-## otherdescr = cpu.fielddescrof(NODE2, 'other')
-## nodesize = cpu.typedescrof(NODE)
-## nodesize2 = cpu.typedescrof(NODE2)
-
-## arraydescr = cpu.arraydescrof(ootype.Array(ootype.Signed))
-## floatarraydescr = cpu.arraydescrof(ootype.Array(ootype.Float))
-
-## # a plain Record
-## S = ootype.Record({'a': ootype.Signed, 'b': NODE})
-## ssize = cpu.typedescrof(S)
-## adescr = cpu.fielddescrof(S, 'a')
-## bdescr = cpu.fielddescrof(S, 'b')
-## sbox = BoxObj(ootype.cast_to_object(ootype.new(S)))
-## arraydescr2 = cpu.arraydescrof(ootype.Array(S))
-
-## T = ootype.Record({'c': ootype.Signed,
-## 'd': ootype.Array(NODE)})
-## tsize = cpu.typedescrof(T)
-## cdescr = cpu.fielddescrof(T, 'c')
-## ddescr = cpu.fielddescrof(T, 'd')
-## arraydescr3 = cpu.arraydescrof(ootype.Array(NODE))
-
-## U = ootype.Instance('U', ootype.ROOT, {'one': ootype.Array(NODE)})
-## usize = cpu.typedescrof(U)
-## onedescr = cpu.fielddescrof(U, 'one')
-## u_vtable = ootype.runtimeClass(U)
-## u_vtable_adr = ootype.cast_to_object(u_vtable)
-
-## # force a consistent order
-## valuedescr.sort_key()
-## nextdescr.sort_key()
-## adescr.sort_key()
-## bdescr.sort_key()
-
-## FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
-## nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) # XXX fix ootype
-
-## cpu.class_sizes = {node_vtable_adr: cpu.typedescrof(NODE),
-## node_vtable_adr2: cpu.typedescrof(NODE2),
-## u_vtable_adr: cpu.typedescrof(U)}
-## namespace = locals()
-
-class BaseTest(object):
- invent_fail_descr = None
-
- def parse(self, s, boxkinds=None):
- return parse(s, self.cpu, self.namespace,
- type_system=self.type_system,
- boxkinds=boxkinds,
- invent_fail_descr=self.invent_fail_descr)
-
- def unpack_specnodes(self, text):
- #
- def constclass(cls_vtable):
- if self.type_system == 'lltype':
- return ConstInt(adr2int(llmemory.cast_ptr_to_adr(cls_vtable)))
- else:
- return ConstObj(ootype.cast_to_object(cls_vtable))
- def constant(value):
- if isinstance(lltype.typeOf(value), lltype.Ptr):
- return ConstPtr(value)
- elif isinstance(ootype.typeOf(value), ootype.OOType):
- return ConstObj(ootype.cast_to_object(value))
- else:
- return ConstInt(value)
-
- def parsefields(kwds_fields):
- fields = []
- for key, value in kwds_fields.items():
- fields.append((self.namespace[key], value))
- fields.sort(key = lambda (x, _): x.sort_key())
- return fields
- def makeConstant(value):
- return ConstantSpecNode(constant(value))
- def makeVirtual(cls_vtable, **kwds_fields):
- fields = parsefields(kwds_fields)
- return VirtualInstanceSpecNode(constclass(cls_vtable), fields)
- def makeVirtualArray(arraydescr, *items):
- return VirtualArraySpecNode(arraydescr, items)
- def makeVirtualStruct(typedescr, **kwds_fields):
- fields = parsefields(kwds_fields)
- return VirtualStructSpecNode(typedescr, fields)
- #
- context = {'Not': prebuiltNotSpecNode,
- 'Constant': makeConstant,
- 'Virtual': makeVirtual,
- 'VArray': makeVirtualArray,
- 'VStruct': makeVirtualStruct}
- lst = eval('[' + text + ']', self.namespace, context)
- return lst
-
- def check_specnodes(self, specnodes, text):
- lst = self.unpack_specnodes(text)
- assert len(specnodes) == len(lst)
- for x, y in zip(specnodes, lst):
- assert x.equals(y, ge=False)
- return True
-
-# ____________________________________________________________
-
-class BaseTestOptimizeFindNode(BaseTest):
-
- def find_nodes(self, ops, spectext, boxkinds=None):
- assert boxkinds is None or isinstance(boxkinds, dict)
- loop = self.parse(ops, boxkinds=boxkinds)
- perfect_specialization_finder = PerfectSpecializationFinder(self.cpu)
- perfect_specialization_finder.find_nodes_loop(loop)
- self.check_specnodes(loop.token.specnodes, spectext)
- return (loop.getboxes(), perfect_specialization_finder.getnode)
-
- def test_find_nodes_simple(self):
- ops = """
- [i]
- i0 = int_sub(i, 1)
- guard_value(i0, 0) [i0]
- jump(i0)
- """
- boxes, getnode = self.find_nodes(ops, 'Not')
- assert getnode(boxes.i).fromstart
- assert not getnode(boxes.i0).fromstart
-
- def test_find_nodes_non_escape(self):
- ops = """
- [p0]
- p1 = getfield_gc(p0, descr=nextdescr)
- i0 = getfield_gc(p1, descr=valuedescr)
- i1 = int_sub(i0, 1)
- p2 = getfield_gc(p0, descr=nextdescr)
- setfield_gc(p2, i1, descr=valuedescr)
- p3 = new_with_vtable(ConstClass(node_vtable))
- jump(p3)
- """
- boxes, getnode = self.find_nodes(ops,
- 'Virtual(node_vtable, nextdescr=Not)')
- assert not getnode(boxes.p0).escaped
- assert getnode(boxes.p1).escaped
- assert getnode(boxes.p2).escaped
- assert getnode(boxes.p0).fromstart
- assert getnode(boxes.p1).fromstart
- assert getnode(boxes.p2).fromstart
-
- def test_find_nodes_escape(self):
- ops = """
- [p0]
- p1 = getfield_gc(p0, descr=nextdescr)
- p2 = getfield_gc(p1, descr=nextdescr)
- i0 = getfield_gc(p2, descr=valuedescr)
- i1 = int_sub(i0, 1)
- escape(p1)
- p3 = getfield_gc(p0, descr=nextdescr)
- setfield_gc(p3, i1, descr=valuedescr)
- p4 = getfield_gc(p1, descr=nextdescr)
- setfield_gc(p4, i1, descr=valuedescr)
- p5 = new_with_vtable(ConstClass(node_vtable))
- jump(p5)
- """
- boxes, getnode = self.find_nodes(ops,
- 'Virtual(node_vtable, nextdescr=Not)')
- assert not getnode(boxes.p0).escaped
- assert getnode(boxes.p1).escaped
- assert getnode(boxes.p2).escaped # forced by p1
- assert getnode(boxes.p3).escaped # forced because p3 == p1
- assert getnode(boxes.p4).escaped # forced by p1
- assert getnode(boxes.p0).fromstart
- assert getnode(boxes.p1).fromstart
- assert getnode(boxes.p2).fromstart
- assert getnode(boxes.p3).fromstart
- assert not getnode(boxes.p4).fromstart
-
- def test_find_nodes_new_1(self):
- ops = """
- [p1]
- p2 = new_with_vtable(ConstClass(node_vtable))
- jump(p2)
- """
- boxes, getnode = self.find_nodes(ops, 'Virtual(node_vtable)')
-
- boxp1 = getnode(boxes.p1)
- boxp2 = getnode(boxes.p2)
- assert not boxp1.escaped
- assert not boxp2.escaped
-
- assert not boxp1.origfields
- assert not boxp1.curfields
- assert not boxp2.origfields
- assert not boxp2.curfields
-
- assert boxp1.fromstart
- assert not boxp2.fromstart
-
- assert boxp1.knownclsbox is None
- assert boxp2.knownclsbox.getaddr() == self.node_vtable_adr
-
- def test_find_nodes_new_2(self):
- ops = """
- [i1, p1]
- p2 = new_with_vtable(ConstClass(node_vtable))
- p3 = new_with_vtable(ConstClass(node_vtable2))
- setfield_gc(p2, p3, descr=nextdescr)
- setfield_gc(p3, i1, descr=valuedescr)
- jump(i1, p2)
- """
- self.find_nodes(ops,
- '''Not,
- Virtual(node_vtable,
- nextdescr=Virtual(node_vtable2,
- valuedescr=Not))''')
-
- def test_find_nodes_new_3(self):
- ops = """
- [sum, p1]
- guard_class(p1, ConstClass(node_vtable)) []
- i1 = getfield_gc(p1, descr=valuedescr)
- i2 = int_sub(i1, 1)
- sum2 = int_add(sum, i1)
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p2, i2, descr=valuedescr)
- p3 = new_with_vtable(ConstClass(node_vtable2))
- setfield_gc(p2, p3, descr=nextdescr)
- jump(sum2, p2)
- """
- boxes, getnode = self.find_nodes(
- ops,
- '''Not,
- Virtual(node_vtable,
- valuedescr=Not,
- nextdescr=Virtual(node_vtable2))''',
- boxkinds={'sum': BoxInt, 'sum2': BoxInt})
- assert getnode(boxes.sum) is not getnode(boxes.sum2)
- assert getnode(boxes.p1) is not getnode(boxes.p2)
-
- boxp1 = getnode(boxes.p1)
- boxp2 = getnode(boxes.p2)
- boxp3 = getnode(boxes.p3)
- assert not boxp1.escaped
- assert not boxp2.escaped
- assert not boxp3.escaped
-
- assert not boxp1.curfields
- assert boxp1.origfields[self.valuedescr] is getnode(boxes.i1)
- assert not boxp2.origfields
- assert boxp2.curfields[self.nextdescr] is boxp3
-
- assert boxp1.fromstart
- assert not boxp2.fromstart
- assert not boxp3.fromstart
-
- assert boxp2.knownclsbox.getaddr() == self.node_vtable_adr
- assert boxp3.knownclsbox.getaddr() == self.node_vtable_adr2
-
- def test_find_nodes_new_aliasing_0(self):
- ops = """
- [p1, p2]
- p3 = new_with_vtable(ConstClass(node_vtable))
- jump(p3, p3)
- """
- # both p1 and p2 must be NotSpecNodes; it's not possible to pass
- # the same Virtual both in p1 and p2 (at least so far).
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_new_aliasing_1(self):
- ops = """
- [sum, p1]
- guard_class(p1, ConstClass(node_vtable)) []
- p3 = getfield_gc(p1, descr=nextdescr)
- guard_class(p3, ConstClass(node_vtable)) []
- i1 = getfield_gc(p1, descr=valuedescr)
- i2 = int_sub(i1, 1)
- sum2 = int_add(sum, i1)
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p2, i2, descr=valuedescr)
- setfield_gc(p2, p2, descr=nextdescr)
- jump(sum2, p2)
- """
- # the issue is the cycle "p2->p2", which cannot be represented
- # with SpecNodes so far
- self.find_nodes(ops, 'Not, Not',
- boxkinds={'sum': BoxInt, 'sum2': BoxInt})
-
- def test_find_nodes_new_aliasing_2(self):
- ops = """
- [p1, p2]
- escape(p2)
- p3 = new_with_vtable(ConstClass(node_vtable))
- jump(p3, p3)
- """
- # both p1 and p2 must be NotSpecNodes; it's not possible to pass
- # in p1 a Virtual and not in p2, as they both come from the same p3.
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_new_mismatch(self):
- ops = """
- [p1]
- guard_class(p1, ConstClass(node_vtable)) []
- p2 = new_with_vtable(ConstClass(node_vtable2))
- jump(p2)
- """
- # this is not a valid loop at all, because of the mismatch
- # between the produced and the consumed class.
- py.test.raises(InvalidLoop, self.find_nodes, ops, None)
-
- def test_find_nodes_new_aliasing_mismatch(self):
- ops = """
- [p0, p1]
- guard_class(p0, ConstClass(node_vtable)) []
- guard_class(p1, ConstClass(node_vtable2)) []
- p2 = new_with_vtable(ConstClass(node_vtable2))
- jump(p2, p2)
- """
- # this is also not really a valid loop, but it's not detected
- # because p2 is passed more than once in the jump().
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_new_escapes(self):
- ops = """
- [p0]
- escape(p0)
- p1 = new_with_vtable(ConstClass(node_vtable))
- jump(p1)
- """
- self.find_nodes(ops, 'Not')
-
- def test_find_nodes_new_unused(self):
- ops = """
- [p0]
- p1 = new_with_vtable(ConstClass(node_vtable))
- p2 = new_with_vtable(ConstClass(node_vtable))
- p3 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, p2, descr=nextdescr)
- setfield_gc(p2, p3, descr=nextdescr)
- jump(p1)
- """
- self.find_nodes(ops, '''
- Virtual(node_vtable,
- nextdescr=Virtual(node_vtable,
- nextdescr=Virtual(node_vtable)))''')
-
- def test_find_nodes_ptr_eq(self):
- ops = """
- [p3, p4, p2]
- p0 = new_with_vtable(ConstClass(node_vtable))
- p1 = new_with_vtable(ConstClass(node_vtable))
- guard_nonnull(p0) []
- i3 = ptr_ne(p0, NULL)
- guard_true(i3) []
- i4 = ptr_eq(p0, NULL)
- guard_false(i4) []
- i5 = ptr_ne(NULL, p0)
- guard_true(i5) []
- i6 = ptr_eq(NULL, p0)
- guard_false(i6) []
- i7 = ptr_ne(p0, p1)
- guard_true(i7) []
- i8 = ptr_eq(p0, p1)
- guard_false(i8) []
- i9 = ptr_ne(p0, p2)
- guard_true(i9) []
- i10 = ptr_eq(p0, p2)
- guard_false(i10) []
- i11 = ptr_ne(p2, p1)
- guard_true(i11) []
- i12 = ptr_eq(p2, p1)
- guard_false(i12) []
- jump(p0, p1, p2)
- """
- self.find_nodes(ops, '''Virtual(node_vtable),
- Virtual(node_vtable),
- Not''')
-
- def test_find_nodes_call(self):
- ops = """
- [i0, p2]
- p0 = new_with_vtable(ConstClass(node_vtable))
- i1 = call_pure(i0, p0) # forces p0 to not be virtual
- jump(i1, p0)
- """
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_default_field(self):
- ops = """
- [p0]
- i0 = getfield_gc(p0, descr=valuedescr)
- guard_value(i0, 5) []
- p1 = new_with_vtable(ConstClass(node_vtable))
- # the field 'value' has its default value of 0
- jump(p1)
- """
- # The answer must contain the 'value' field, because otherwise
- # we might get incorrect results: when tracing, i0 was 5.
- self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)')
-
- def test_find_nodes_nonvirtual_guard_class(self):
- ops = """
- [p1]
- guard_class(p1, ConstClass(node_vtable)) [p1]
- jump(p1)
- """
- self.find_nodes(ops, 'Not')
-
- def test_find_nodes_p12_simple(self):
- ops = """
- [p1]
- i3 = getfield_gc(p1, descr=valuedescr)
- escape(i3)
- jump(p1)
- """
- self.find_nodes(ops, 'Not')
-
- def test_find_nodes_p123_simple(self):
- ops = """
- [i1, p2, p3]
- i3 = getfield_gc(p3, descr=valuedescr)
- escape(i3)
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i1, descr=valuedescr)
- jump(i1, p1, p2)
- """
- # We cannot track virtuals that survive for more than two iterations.
- self.find_nodes(ops, 'Not, Not, Not')
-
- def test_find_nodes_p1234_simple(self):
- ops = """
- [i1, p2, p3, p4]
- i4 = getfield_gc(p4, descr=valuedescr)
- escape(i4)
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i1, descr=valuedescr)
- jump(i1, p1, p2, p3)
- """
- # We cannot track virtuals that survive for more than two iterations.
- self.find_nodes(ops, 'Not, Not, Not, Not')
-
- def test_find_nodes_p123_guard_class(self):
- ops = """
- [i1, p2, p3]
- guard_class(p3, ConstClass(node_vtable)) [i1, p2, p3]
- i3 = getfield_gc(p3, descr=valuedescr)
- escape(i3)
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i1, descr=valuedescr)
- jump(i1, p1, p2)
- """
- # We cannot track virtuals that survive for more than two iterations.
- self.find_nodes(ops, 'Not, Not, Not')
-
- def test_find_nodes_p123_rec(self):
- ops = """
- [i1, p2, p0d]
- p3 = getfield_gc(p0d, descr=nextdescr)
- i3 = getfield_gc(p3, descr=valuedescr)
- escape(i3)
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i1, descr=valuedescr)
- p0c = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p0c, p2, descr=nextdescr)
- jump(i1, p1, p0c)
- """
- # We cannot track virtuals that survive for more than two iterations.
- self.find_nodes(ops, '''Not,
- Not,
- Virtual(node_vtable, nextdescr=Not)''')
-
- def test_find_nodes_setfield_bug(self):
- ops = """
- [p1, p2]
- escape(p1)
- setfield_gc(p1, p2, descr=nextdescr)
- p3 = new_with_vtable(ConstClass(node_vtable))
- jump(p1, p3)
- """
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_array_virtual_1(self):
- ops = """
- [i1, p2]
- i2 = getarrayitem_gc(p2, 1, descr=arraydescr)
- escape(i2)
- p3 = new_array(3, descr=arraydescr)
- setarrayitem_gc(p3, 1, i1, descr=arraydescr)
- jump(i1, p3)
- """
- self.find_nodes(ops, 'Not, VArray(arraydescr, Not, Not, Not)')
-
- def test_find_nodes_array_virtual_2(self):
- ops = """
- [i1, p2]
- i2 = arraylen_gc(p2, descr=arraydescr)
- escape(i2)
- p3 = new_array(3, descr=arraydescr)
- setarrayitem_gc(p3, 1, i1, descr=arraydescr)
- jump(i1, p3)
- """
- self.find_nodes(ops, 'Not, VArray(arraydescr, Not, Not, Not)')
-
- def test_find_nodes_array_virtual_3(self):
- ops = """
- [pvalue1, p2]
- pvalue2 = new_with_vtable(ConstClass(node_vtable2))
- ps2 = getarrayitem_gc(p2, 1, descr=arraydescr)
- setfield_gc(ps2, pvalue2, descr=nextdescr)
- ps3 = getarrayitem_gc(p2, 1, descr=arraydescr)
- pvalue3 = getfield_gc(ps3, descr=nextdescr)
- ps1 = new_with_vtable(ConstClass(node_vtable))
- p3 = new_array(3, descr=arraydescr)
- setarrayitem_gc(p3, 1, ps1, descr=arraydescr)
- jump(pvalue3, p3)
- """
- self.find_nodes(ops, 'Virtual(node_vtable2), VArray(arraydescr, Not, Virtual(node_vtable), Not)')
-
- def test_find_nodes_array_virtual_empty(self):
- ops = """
- [i1, p2]
- p3 = new_array(3, descr=arraydescr)
- jump(i1, p3)
- """
- self.find_nodes(ops, 'Not, VArray(arraydescr, Not, Not, Not)')
-
- def test_find_nodes_array_nonvirtual_1(self):
- ops = """
- [i1, p2]
- i2 = getarrayitem_gc(p2, i1, descr=arraydescr)
- escape(i2)
- p3 = new_array(4, descr=arraydescr)
- setarrayitem_gc(p3, i1, i2, descr=arraydescr)
- jump(i1, p3)
- """
- # Does not work because of the variable index, 'i1'.
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_array_forced_1(self):
- ops = """
- [p1, i1]
- p2 = new_array(1, descr=arraydescr)
- setarrayitem_gc(p2, 0, p1, descr=arraydescr)
- p3 = getarrayitem_gc(p2, i1, descr=arraydescr)
- p4 = new_with_vtable(ConstClass(node_vtable))
- jump(p4, i1)
- """
- # escapes because getarrayitem_gc uses a non-constant index
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_arrayitem_forced(self):
- ops = """
- [p1]
- p2 = new_array(1, descr=arraydescr)
- escape(p2)
- p4 = new_with_vtable(ConstClass(node_vtable))
- setarrayitem_gc(p2, 0, p4, descr=arraydescr)
- jump(p4)
- """
- self.find_nodes(ops, 'Not')
-
- def test_find_nodes_struct_virtual_1(self):
- ops = """
- [i1, p2]
- i2 = getfield_gc(p2, descr=adescr)
- escape(i2)
- p3 = new(descr=ssize)
- setfield_gc(p3, i1, descr=adescr)
- jump(i1, p3)
- """
- self.find_nodes(ops, 'Not, VStruct(ssize, adescr=Not)')
-
- def test_find_nodes_struct_nonvirtual_1(self):
- ops = """
- [i1, p2]
- i2 = getfield_gc(p2, descr=adescr)
- escape(p2)
- p3 = new(descr=ssize)
- setfield_gc(p3, i1, descr=adescr)
- jump(i1, p3)
- """
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_guard_value_constant(self):
- ops = """
- [p1]
- guard_value(p1, ConstPtr(myptr)) []
- jump(ConstPtr(myptr))
- """
- self.find_nodes(ops, 'Constant(myptr)')
-
- def test_find_nodes_guard_value_constant_mismatch(self):
- ops = """
- [p1]
- guard_value(p1, ConstPtr(myptr2)) []
- jump(ConstPtr(myptr))
- """
- py.test.raises(InvalidLoop, self.find_nodes, ops, None)
-
- def test_find_nodes_guard_value_escaping_constant(self):
- ops = """
- [p1]
- escape(p1)
- guard_value(p1, ConstPtr(myptr)) []
- jump(ConstPtr(myptr))
- """
- self.find_nodes(ops, 'Constant(myptr)')
-
- def test_find_nodes_guard_value_same_as_constant(self):
- ops = """
- [p1]
- guard_value(p1, ConstPtr(myptr)) []
- p2 = same_as(ConstPtr(myptr))
- jump(p2)
- """
- self.find_nodes(ops, 'Constant(myptr)')
-
- def test_find_nodes_store_into_loop_constant_1(self):
- ops = """
- [i0, p1, p4]
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, p2, descr=nextdescr)
- jump(i0, p1, p2)
- """
- self.find_nodes(ops, 'Not, Not, Not')
-
- def test_find_nodes_store_into_loop_constant_2(self):
- ops = """
- [i0, p4, p1]
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, p2, descr=nextdescr)
- jump(i0, p2, p1)
- """
- self.find_nodes(ops, 'Not, Not, Not')
-
- def test_find_nodes_store_into_loop_constant_3(self):
- ops = """
- [i0, p1]
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, p2, descr=nextdescr)
- call(i0)
- jump(i0, p1)
- """
- self.find_nodes(ops, 'Not, Not')
-
- def test_find_nodes_arithmetic_propagation_bug_0(self):
- ops = """
- [p1]
- i1 = getarrayitem_gc(p1, 0, descr=arraydescr)
- escape(i1)
- i2 = int_add(0, 1)
- p2 = new_array(i2, descr=arraydescr)
- i3 = escape()
- setarrayitem_gc(p2, 0, i3, descr=arraydescr)
- jump(p2)
- """
- self.find_nodes(ops, 'VArray(arraydescr, Not)')
-
- def test_find_nodes_arithmetic_propagation_bug_1(self):
- ops = """
- [p1]
- i1 = getarrayitem_gc(p1, 0, descr=arraydescr)
- escape(i1)
- i2 = same_as(1)
- p2 = new_array(i2, descr=arraydescr)
- setarrayitem_gc(p2, 0, 5)
- jump(p2)
- """
- self.find_nodes(ops, 'VArray(arraydescr, Not)')
-
- def test_find_nodes_arithmetic_propagation_bug_2(self):
- ops = """
- [p1]
- i0 = int_sub(17, 17)
- i1 = getarrayitem_gc(p1, i0, descr=arraydescr)
- escape(i1)
- i2 = int_add(0, 1)
- p2 = new_array(i2, descr=arraydescr)
- i3 = escape()
- setarrayitem_gc(p2, i0, i3, descr=arraydescr)
- jump(p2)
- """
- self.find_nodes(ops, 'VArray(arraydescr, Not)')
-
- def test_find_nodes_arithmetic_propagation_bug_3(self):
- ops = """
- [p1]
- i1 = getarrayitem_gc(p1, 0, descr=arraydescr)
- escape(i1)
- p3 = new_array(1, descr=arraydescr)
- i2 = arraylen_gc(p3, descr=arraydescr)
- p2 = new_array(i2, descr=arraydescr)
- i3 = escape()
- setarrayitem_gc(p2, 0, i3, descr=arraydescr)
- jump(p2)
- """
- self.find_nodes(ops, 'VArray(arraydescr, Not)')
-
- def test_find_nodes_bug_1(self):
- ops = """
- [p12]
- guard_nonnull(p12) []
- guard_class(p12, ConstClass(node_vtable)) []
- guard_class(p12, ConstClass(node_vtable)) []
- i22 = getfield_gc_pure(p12, descr=valuedescr)
- escape(i22)
- guard_nonnull(p12) []
- guard_class(p12, ConstClass(node_vtable)) []
- guard_class(p12, ConstClass(node_vtable)) []
- i29 = getfield_gc_pure(p12, descr=valuedescr)
- i31 = int_add_ovf(i29, 1)
- guard_no_overflow() []
- p33 = new_with_vtable(ConstClass(node_vtable)) # NODE
- setfield_gc(p33, i31, descr=valuedescr)
- #
- p35 = new_array(1, descr=arraydescr3) # Array(NODE)
- setarrayitem_gc(p35, 0, p33, descr=arraydescr3)
- p38 = new_with_vtable(ConstClass(u_vtable)) # U
- setfield_gc(p38, p35, descr=onedescr)
- guard_nonnull(p38) []
- guard_nonnull(p38) []
- guard_class(p38, ConstClass(u_vtable)) []
- p42 = getfield_gc(p38, descr=onedescr) # Array(NODE)
- i43 = arraylen_gc(p42, descr=arraydescr3)
- i45 = int_sub(i43, 0)
- p46 = new(descr=tsize) # T
- setfield_gc(p46, i45, descr=cdescr)
- p47 = new_array(i45, descr=arraydescr3) # Array(NODE)
- setfield_gc(p46, p47, descr=ddescr)
- i48 = int_lt(0, i43)
- guard_true(i48) []
- p49 = getarrayitem_gc(p42, 0, descr=arraydescr3) # NODE
- p50 = getfield_gc(p46, descr=ddescr) # Array(NODE)
- setarrayitem_gc(p50, 0, p49, descr=arraydescr3)
- i52 = int_lt(1, i43)
- guard_false(i52) []
- i53 = getfield_gc(p46, descr=cdescr)
- i55 = int_ne(i53, 1)
- guard_false(i55) []
- p56 = getfield_gc(p46, descr=ddescr) # Array(NODE)
- p58 = getarrayitem_gc(p56, 0, descr=arraydescr3) # NODE
- guard_nonnull(p38) []
- jump(p58)
- """
- self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)')
-
- # ------------------------------
- # Bridge tests
-
- def find_bridge(self, ops, inputspectext, outputspectext, boxkinds=None,
- mismatch=False):
- assert boxkinds is None or isinstance(boxkinds, dict)
- inputspecnodes = self.unpack_specnodes(inputspectext)
- outputspecnodes = self.unpack_specnodes(outputspectext)
- bridge = self.parse(ops, boxkinds=boxkinds)
- bridge_specialization_finder = BridgeSpecializationFinder(self.cpu)
- bridge_specialization_finder.find_nodes_bridge(bridge, inputspecnodes)
- matches = bridge_specialization_finder.bridge_matches(outputspecnodes)
- if mismatch:
- assert not matches
- else:
- assert matches
-
- def test_bridge_simple(self):
- ops = """
- [i0]
- i1 = int_add(i0, 1)
- jump(i1)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'Virtual(node_vtable)', mismatch=True)
-
- def test_bridge_simple_known_class(self):
- ops = """
- [p0]
- setfield_gc(p0, 123, descr=valuedescr)
- jump(p0)
- """
- self.find_bridge(ops, 'Not', 'Not')
-
- def test_bridge_simple_constant(self):
- ops = """
- []
- jump(ConstPtr(myptr))
- """
- self.find_bridge(ops, '', 'Not')
- self.find_bridge(ops, '', 'Constant(myptr)')
- self.find_bridge(ops, '', 'Constant(myptr2)', mismatch=True)
-
- def test_bridge_simple_constant_mismatch(self):
- ops = """
- [p0]
- jump(p0)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'Constant(myptr)', mismatch=True)
-
- def test_bridge_simple_virtual_1(self):
- ops = """
- [i0]
- p0 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p0, i0, descr=valuedescr)
- jump(p0)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'Virtual(node_vtable, valuedescr=Not)')
- self.find_bridge(ops, 'Not',
- '''Virtual(node_vtable,
- valuedescr=Not,
- nextdescr=Not)''')
- #
- self.find_bridge(ops, 'Not', 'Virtual(node_vtable)',
- mismatch=True) # missing valuedescr
- self.find_bridge(ops, 'Not', 'Virtual(node_vtable, nextdescr=Not)',
- mismatch=True) # missing valuedescr
- self.find_bridge(ops, 'Not', 'Virtual(node_vtable2, valuedescr=Not)',
- mismatch=True) # bad class
-
- def test_bridge_simple_virtual_struct(self):
- ops = """
- [i0]
- p0 = new(descr=ssize)
- setfield_gc(p0, i0, descr=adescr)
- jump(p0)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'VStruct(ssize, adescr=Not)')
-
- def test_bridge_simple_virtual_struct_non_unique(self):
- ops = """
- [i0]
- p0 = new(descr=ssize)
- setfield_gc(p0, i0, descr=adescr)
- jump(p0, p0)
- """
- self.find_bridge(ops, 'Not', 'Not, Not')
- self.find_bridge(ops, 'Not', 'VStruct(ssize), VStruct(ssize)',
- mismatch=True)
-
-
- def test_bridge_simple_virtual_2(self):
- ops = """
- [p0]
- setfield_gc(p0, 123, descr=valuedescr)
- jump(p0)
- """
- self.find_bridge(ops, 'Virtual(node_vtable)', 'Not')
- self.find_bridge(ops, 'Virtual(node_vtable)',
- 'Virtual(node_vtable, valuedescr=Not)')
- self.find_bridge(ops, 'Virtual(node_vtable, valuedescr=Not)',
- 'Virtual(node_vtable, valuedescr=Not)')
- self.find_bridge(ops, 'Virtual(node_vtable, valuedescr=Not)',
- '''Virtual(node_vtable,
- valuedescr=Not,
- nextdescr=Not)''')
- self.find_bridge(ops, '''Virtual(node_vtable,
- valuedescr=Not,
- nextdescr=Not)''',
- '''Virtual(node_vtable,
- valuedescr=Not,
- nextdescr=Not)''')
- #
- self.find_bridge(ops, 'Virtual(node_vtable)', 'Virtual(node_vtable)',
- mismatch=True) # because of missing valuedescr
- self.find_bridge(ops, 'Virtual(node_vtable)',
- 'Virtual(node_vtable2, valuedescr=Not)',
- mismatch=True) # bad class
-
- def test_bridge_virtual_mismatch_1(self):
- ops = """
- [i0]
- p0 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p0, i0, descr=valuedescr)
- jump(p0, p0)
- """
- self.find_bridge(ops, 'Not', 'Not, Not')
- #
- self.find_bridge(ops, 'Not',
- '''Virtual(node_vtable, valuedescr=Not),
- Virtual(node_vtable, valuedescr=Not)''',
- mismatch=True) # duplicate p0
-
- def test_bridge_guard_class(self):
- ops = """
- [p1]
- p2 = getfield_gc(p1, descr=nextdescr)
- guard_class(p2, ConstClass(node_vtable)) []
- jump(p2)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Virtual(node_vtable2, nextdescr=Not)', 'Not')
- self.find_bridge(ops,
- '''Virtual(node_vtable,
- nextdescr=Virtual(node_vtable,
- nextdescr=Not))''',
- '''Virtual(node_vtable,
- nextdescr=Not)''')
- #
- self.find_bridge(ops, 'Not', 'Virtual(node_vtable)',
- mismatch=True)
-
- def test_bridge_unused(self):
- ops = """
- []
- p1 = new_with_vtable(ConstClass(node_vtable))
- p2 = new_with_vtable(ConstClass(node_vtable))
- p3 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, p2, descr=nextdescr)
- setfield_gc(p2, p3, descr=nextdescr)
- jump(p1)
- """
- self.find_bridge(ops, '',
- '''Not''')
- self.find_bridge(ops, '',
- '''Virtual(node_vtable,
- nextdescr=Not)''')
- self.find_bridge(ops, '',
- '''Virtual(node_vtable,
- nextdescr=Virtual(node_vtable,
- nextdescr=Not))''')
- self.find_bridge(ops, '',
- '''Virtual(node_vtable,
- nextdescr=Virtual(node_vtable,
- nextdescr=Virtual(node_vtable)))''')
- self.find_bridge(ops, '',
- '''Virtual(node_vtable,
- nextdescr=Virtual(node_vtable,
- nextdescr=Virtual(node_vtable,
- nextdescr=Not)))''')
-
- def test_bridge_to_finish(self):
- ops = """
- [i1]
- i2 = int_add(i1, 5)
- finish(i2)
- """
- self.find_bridge(ops, 'Not', 'Not')
-
- def test_bridge_virtual_to_finish(self):
- ops = """
- [i1]
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i1, descr=valuedescr)
- finish(p1)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not',
- 'Virtual(node_vtable, valuedescr=Not)',
- mismatch=True)
-
- def test_bridge_array_virtual_1(self):
- ops = """
- [i1]
- p1 = new_array(3, descr=arraydescr)
- setarrayitem_gc(p1, 0, i1, descr=arraydescr)
- jump(p1)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'VArray(arraydescr, Not, Not, Not)')
-
- def test_bridge_array_virtual_size_mismatch(self):
- ops = """
- [i1]
- p1 = new_array(5, descr=arraydescr)
- setarrayitem_gc(p1, 0, i1, descr=arraydescr)
- jump(p1)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'VArray(arraydescr, Not, Not, Not)',
- mismatch=True)
-
- def test_bridge_array_virtual_2(self):
- ops = """
- [i1]
- p1 = new_array(3, descr=arraydescr)
- setarrayitem_gc(p1, 0, i1, descr=arraydescr)
- escape(p1)
- jump(p1)
- """
- self.find_bridge(ops, 'Not', 'Not')
- self.find_bridge(ops, 'Not', 'VArray(arraydescr, Not, Not, Not)',
- mismatch=True)
-
- def test_bridge_nested_structs(self):
- ops = """
- []
- p1 = new_with_vtable(ConstClass(node_vtable))
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, p2, descr=nextdescr)
- jump(p1)
- """
- self.find_bridge(ops, '', 'Not')
- self.find_bridge(ops, '', 'Virtual(node_vtable, nextdescr=Not)')
- self.find_bridge(ops, '',
- 'Virtual(node_vtable, nextdescr=Virtual(node_vtable))')
- self.find_bridge(ops, '',
- 'Virtual(node_vtable, nextdescr=Virtual(node_vtable2))',
- mismatch=True)
-
-
-class TestLLtype(BaseTestOptimizeFindNode, LLtypeMixin):
- pass
-
-##class TestOOtype(BaseTestOptimizeFindNode, OOtypeMixin):
-## def test_find_nodes_instanceof(self):
-## ops = """
-## [i0]
-## p0 = new_with_vtable(ConstClass(node_vtable))
-## i1 = instanceof(p0, descr=nodesize)
-## jump(i1)
-## """
-## boxes, getnode = self.find_nodes(ops, 'Not')
-## assert not getnode(boxes.p0).escaped
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -202,6 +202,7 @@
llimpl.compile_add_fail_arg(c, var2index[box])
else:
llimpl.compile_add_fail_arg(c, -1)
+
x = op.result
if x is not None:
if isinstance(x, history.BoxInt):
diff --git a/pypy/jit/metainterp/test/test_loop_nopspec.py b/pypy/jit/metainterp/test/test_loop_nopspec.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_loop_nopspec.py
+++ /dev/null
@@ -1,27 +0,0 @@
-
-from pypy.jit.metainterp.test import test_loop, test_send
-from pypy.jit.metainterp.warmspot import ll_meta_interp
-from pypy.rlib.jit import OPTIMIZER_NO_PERFECTSPEC
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-
-class LoopNoPSpecTest(test_send.SendTests):
- def meta_interp(self, func, args, **kwds):
- return ll_meta_interp(func, args, optimizer=OPTIMIZER_NO_PERFECTSPEC,
- CPUClass=self.CPUClass,
- type_system=self.type_system,
- **kwds)
-
- def check_loops(self, *args, **kwds):
- pass
-
- def check_loop_count(self, count):
- pass
-
- def check_jumps(self, maxcount):
- pass
-
-class TestLLtype(LoopNoPSpecTest, LLJitMixin):
- pass
-
-class TestOOtype(LoopNoPSpecTest, OOJitMixin):
- pass
diff --git a/pypy/jit/metainterp/viewnode.py b/pypy/jit/metainterp/viewnode.py
deleted file mode 100644
--- a/pypy/jit/metainterp/viewnode.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import py
-from pypy.jit.metainterp import specnode, optimizefindnode
-from pypy.tool.pairtype import extendabletype
-
-class __extend__(specnode.NotSpecNode):
- def _dot(self, seen):
- if self in seen:
- return
- seen.add(self)
- yield '%s [label="<Not>"]' % (id(self), )
-
-class __extend__(specnode.ConstantSpecNode):
- def _dot(self, seen):
- if self in seen:
- return
- seen.add(self)
- yield '%s [label="<Const: %s>"]' % (id(self), self.constbox)
-
-class __extend__(specnode.AbstractVirtualStructSpecNode):
- def _dot(self, seen):
- if self in seen:
- return
- seen.add(self)
- yield '%s [label="<%s>"]' % (
- id(self),
- self.__class__.__name__[:-len("SpecNode")])
- for label, node in self.fields:
- yield '%s -> %s [label="%s"]' % (id(self), id(node), label.name)
- for line in node._dot(seen):
- yield line
-
-class __extend__(specnode.VirtualArraySpecNode):
- def _dot(self, seen):
- if self in seen:
- return
- seen.add(self)
- yield '%s [label="<Array: %s>"]' % (
- id(self),
- len(self.items))
- for i, node in enumerate(self.items):
- yield '%s -> %s [label="%s"]' % (id(self), id(node), i)
- for line in node._dot(seen):
- yield line
-
-
-class __extend__(optimizefindnode.InstanceNode):
- __metaclass__ = extendabletype # evil
-
- def _dot(self, seen):
- if self in seen:
- return
- seen.add(self)
- if self.knownclsbox:
- name = "Virtual "
- if isinstance(self.knownclsbox.value, int):
- name += str(self.knownclsbox.value)
- else:
- name += str(self.knownclsbox.value.adr.ptr).rpartition("_vtable")[0].rpartition('.')[2]
- elif self.structdescr:
- name = "Struct " + str(self.structdescr)
- elif self.arraydescr:
- name = "Array"
- else:
- name = "Not"
- if self.escaped:
- name = "ESC " + name
- if self.fromstart:
- name = "START " + name
- if self.unique == optimizefindnode.UNIQUE_NO:
- color = "blue"
- else:
- color = "black"
-
- yield 'orig%s [label="in: [%s]", shape=box, color=%s]' % (
- id(self), name, color)
- yield '%s [label="out: [%s]", shape=box, color=%s]' % (
- id(self), name, color)
- yield 'orig%s -> %s [color=red]' % (id(self), id(self))
- if self.origfields:
- for descr, node in self.origfields.iteritems():
- yield 'orig%s -> orig%s [label="%s"]' % (id(self), id(node), descr.name)
- for line in node._dot(seen):
- yield line
- if self.curfields:
- for descr, node in self.curfields.iteritems():
- yield '%s -> %s [label="%s"]' % (id(self), id(node), descr.name)
- for line in node._dot(seen):
- yield line
- if self.origitems:
- for i, node in sorted(self.origitems.iteritems()):
- yield 'orig%s -> orig%s [label="%s"]' % (id(self), id(node), i)
- for line in node._dot(seen):
- yield line
- if self.curitems:
- for i, node in sorted(self.curitems.iteritems()):
- yield '%s -> %s [label="%s"]' % (id(self), id(node), i)
- for line in node._dot(seen):
- yield line
-
-
-def view(*objects):
- from dotviewer import graphclient
- content = ["digraph G{"]
- seen = set()
- for obj in objects:
- content.extend(obj._dot(seen))
- content.append("}")
- p = py.test.ensuretemp("specnodes").join("temp.dot")
- p.write("\n".join(content))
- graphclient.display_dot_file(str(p))
-
-def viewnodes(l1, l2):
- from dotviewer import graphclient
- content = ["digraph G{"]
- seen = set()
- for obj in l1 + l2:
- content.extend(obj._dot(seen))
- for i, (o1, o2) in enumerate(zip(l1, l2)):
- content.append("%s -> %s [color=green]" % (id(o1), i))
- content.append("%s -> orig%s [color=green]" % (i, id(o2)))
- content.append("}")
- p = py.test.ensuretemp("specnodes").join("temp.dot")
- p.write("\n".join(content))
- graphclient.display_dot_file(str(p))
diff --git a/pypy/jit/backend/x86/test/test_loop_spec.py b/pypy/jit/backend/x86/test/test_loop_spec.py
deleted file mode 100644
--- a/pypy/jit/backend/x86/test/test_loop_spec.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import py
-from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
-from pypy.jit.metainterp.test import test_loop_spec
-
-class TestLoopSpec(Jit386Mixin, test_loop_spec.LoopSpecTest):
- # for the individual tests see
- # ====> ../../../metainterp/test/test_loop.py
- pass
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -373,6 +373,13 @@
else:
log.info("compiling new bridge")
+def compile_add_guard_jump_target(loop, loop_target):
+ loop = _from_opaque(loop)
+ loop_target = _from_opaque(loop_target)
+ op = loop.operations[-1]
+ assert op.is_guard()
+ op.jump_target = loop_target
+
def compile_add_fail(loop, fail_index):
loop = _from_opaque(loop)
index = len(loop.operations)-1
@@ -1634,6 +1641,7 @@
setannotation(compile_add_ref_result, annmodel.SomeInteger())
setannotation(compile_add_float_result, annmodel.SomeInteger())
setannotation(compile_add_jump_target, annmodel.s_None)
+setannotation(compile_add_guard_jump_target, annmodel.s_None)
setannotation(compile_add_fail, annmodel.SomeInteger())
setannotation(compile_add_fail_arg, annmodel.s_None)
setannotation(compile_redirect_fail, annmodel.s_None)
diff --git a/pypy/jit/metainterp/optimizefindnode.py b/pypy/jit/metainterp/optimizefindnode.py
deleted file mode 100644
--- a/pypy/jit/metainterp/optimizefindnode.py
+++ /dev/null
@@ -1,576 +0,0 @@
-from pypy.jit.metainterp.specnode import SpecNode
-from pypy.jit.metainterp.specnode import NotSpecNode, prebuiltNotSpecNode
-from pypy.jit.metainterp.specnode import ConstantSpecNode
-from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
-from pypy.jit.metainterp.specnode import VirtualArraySpecNode
-from pypy.jit.metainterp.specnode import VirtualStructSpecNode
-from pypy.jit.metainterp.history import AbstractValue, ConstInt, Const
-from pypy.jit.metainterp.resoperation import rop
-from pypy.jit.metainterp.executor import execute_nonspec
-from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs
-from pypy.jit.metainterp.optimizeutil import InvalidLoop
-
-# ____________________________________________________________
-
-UNIQUE_UNKNOWN = '\x00'
-UNIQUE_NO = '\x01'
-UNIQUE_INST = '\x02'
-UNIQUE_ARRAY = '\x03'
-UNIQUE_STRUCT = '\x04'
-
-class InstanceNode(object):
- """An instance of this class is used to match the start and
- the end of the loop, so it contains both 'origfields' that represents
- the field's status at the start and 'curfields' that represents it
- at the current point (== the end when optimizefindnode is complete).
- """
- escaped = False # if True, then all the rest of the info is pointless
- unique = UNIQUE_UNKNOWN # for find_unique_nodes()
-
- # fields used to store the shape of the potential VirtualInstance
- knownclsbox = None # set only on freshly-allocated or fromstart structures
- origfields = None # optimization; equivalent to an empty dict
- curfields = None # optimization; equivalent to an empty dict
-
- knownvaluebox = None # a Const with the value of this box, if constant
-
- # fields used to store the shape of the potential VirtualList
- arraydescr = None # set only on freshly-allocated or fromstart arrays
- #arraysize = .. # valid if and only if arraydescr is not None
- origitems = None # optimization; equivalent to an empty dict
- curitems = None # optimization; equivalent to an empty dict
-
- # fields used to store the shape of the potential VirtualStruct
- structdescr = None # set only on freshly-allocated or fromstart structs
- #origfields = .. # same as above
- #curfields = .. # same as above
-
- dependencies = None
-
- def __init__(self, fromstart=False):
- self.fromstart = fromstart # for loops only: present since the start
-
- def is_constant(self):
- return self.knownvaluebox is not None
-
- def add_escape_dependency(self, other):
- assert not self.escaped
- if self.dependencies is None:
- self.dependencies = []
- self.dependencies.append(other)
-
- def mark_escaped(self):
- # invariant: if escaped=True, then dependencies is None
- if not self.escaped:
- self.escaped = True
- self.unique = UNIQUE_NO
- # ^^^ always set unique to UNIQUE_NO when we set escaped to True.
- # See for example test_find_nodes_store_into_loop_constant_2.
- if self.dependencies is not None:
- deps = self.dependencies
- self.dependencies = None
- for box in deps:
- box.mark_escaped()
-
- def set_unique_nodes(self):
- if self.fromstart:
- self.mark_escaped()
- if self.escaped or self.unique != UNIQUE_UNKNOWN:
- # this node is not suitable for being a virtual, or we
- # encounter it more than once when doing the recursion
- self.unique = UNIQUE_NO
- elif self.knownclsbox is not None:
- self.unique = UNIQUE_INST
- if self.curfields is not None:
- for subnode in self.curfields.itervalues():
- subnode.set_unique_nodes()
- elif self.arraydescr is not None:
- self.unique = UNIQUE_ARRAY
- if self.curitems is not None:
- for subnode in self.curitems.itervalues():
- subnode.set_unique_nodes()
- elif self.structdescr is not None:
- self.unique = UNIQUE_STRUCT
- if self.curfields is not None:
- for subnode in self.curfields.itervalues():
- subnode.set_unique_nodes()
- else:
- assert 0, "most probably unreachable"
-
- def __repr__(self):
- flags = ''
- if self.escaped: flags += 'e'
- if self.fromstart: flags += 's'
- if self.knownclsbox: flags += 'c'
- if self.arraydescr: flags += str(self.arraysize)
- if self.structdescr: flags += 'S'
- return "<InstanceNode (%s)>" % (flags,)
-
-# ____________________________________________________________
-# General find_nodes_xxx() interface, for both loops and bridges
-
-class NodeFinder(object):
- """Abstract base class."""
- node_escaped = InstanceNode()
- node_escaped.unique = UNIQUE_NO
- node_escaped.escaped = True
-
- def __init__(self, cpu):
- self.cpu = cpu
- self.nodes = {} # Box -> InstanceNode
-
- def getnode(self, box):
- if isinstance(box, Const):
- return self.set_constant_node(box, box)
- return self.nodes.get(box, self.node_escaped)
-
- def set_constant_node(self, box, constbox):
- assert isinstance(constbox, Const)
- node = InstanceNode()
- node.unique = UNIQUE_NO
- node.escaped = True
- node.knownvaluebox = constbox
- self.nodes[box] = node
- return node
-
- def get_constant_box(self, box):
- if isinstance(box, Const):
- return box
- try:
- node = self.nodes[box]
- except KeyError:
- return None
- else:
- return node.knownvaluebox
-
- def find_nodes(self, operations):
- for op in operations:
- opnum = op.getopnum()
- for value, func in find_nodes_ops:
- if opnum == value:
- func(self, op)
- break
- else:
- self.find_nodes_default(op)
-
- def find_nodes_default(self, op):
- if op.is_always_pure():
- for i in range(op.numargs()):
- arg = op.getarg(i)
- if self.get_constant_box(arg) is None:
- break
- else:
- # all constant arguments: we can constant-fold
- argboxes = [self.get_constant_box(op.getarg(i))
- for i in range(op.numargs())]
- resbox = execute_nonspec(self.cpu, None,
- op.getopnum(), argboxes, op.getdescr())
- self.set_constant_node(op.result, resbox.constbox())
- # default case: mark the arguments as escaping
- for i in range(op.numargs()):
- self.getnode(op.getarg(i)).mark_escaped()
-
- def find_nodes_no_escape(self, op):
- pass # for operations that don't escape their arguments
-
- find_nodes_PTR_EQ = find_nodes_no_escape
- find_nodes_PTR_NE = find_nodes_no_escape
- ##find_nodes_INSTANCEOF = find_nodes_no_escape
- find_nodes_GUARD_NONNULL = find_nodes_no_escape
- find_nodes_GUARD_ISNULL = find_nodes_no_escape
-
- def find_nodes_NEW_WITH_VTABLE(self, op):
- instnode = InstanceNode()
- box = op.getarg(0)
- assert isinstance(box, Const)
- instnode.knownclsbox = box
- self.nodes[op.result] = instnode
-
- def find_nodes_NEW(self, op):
- instnode = InstanceNode()
- instnode.structdescr = op.getdescr()
- self.nodes[op.result] = instnode
-
- def find_nodes_NEW_ARRAY(self, op):
- lengthbox = op.getarg(0)
- lengthbox = self.get_constant_box(lengthbox)
- if lengthbox is None:
- return # var-sized arrays are not virtual
- arraynode = InstanceNode()
- arraynode.arraysize = lengthbox.getint()
- arraynode.arraydescr = op.getdescr()
- self.nodes[op.result] = arraynode
-
- def find_nodes_ARRAYLEN_GC(self, op):
- arraynode = self.getnode(op.getarg(0))
- if arraynode.arraydescr is not None:
- resbox = ConstInt(arraynode.arraysize)
- self.set_constant_node(op.result, resbox)
-
- def find_nodes_GUARD_CLASS(self, op):
- instnode = self.getnode(op.getarg(0))
- if instnode.fromstart: # only useful (and safe) in this case
- box = op.getarg(1)
- assert isinstance(box, Const)
- instnode.knownclsbox = box
-
- def find_nodes_GUARD_VALUE(self, op):
- instnode = self.getnode(op.getarg(0))
- if instnode.fromstart: # only useful (and safe) in this case
- box = op.getarg(1)
- assert isinstance(box, Const)
- instnode.knownvaluebox = box
-
- def find_nodes_SETFIELD_GC(self, op):
- instnode = self.getnode(op.getarg(0))
- fieldnode = self.getnode(op.getarg(1))
- if instnode.escaped:
- fieldnode.mark_escaped()
- return # nothing to be gained from tracking the field
- field = op.getdescr()
- assert isinstance(field, AbstractValue)
- if instnode.curfields is None:
- instnode.curfields = {}
- instnode.curfields[field] = fieldnode
- instnode.add_escape_dependency(fieldnode)
-
- def find_nodes_GETFIELD_GC(self, op):
- instnode = self.getnode(op.getarg(0))
- if instnode.escaped:
- return # nothing to be gained from tracking the field
- field = op.getdescr()
- assert isinstance(field, AbstractValue)
- if instnode.curfields is not None and field in instnode.curfields:
- fieldnode = instnode.curfields[field]
- elif instnode.origfields is not None and field in instnode.origfields:
- fieldnode = instnode.origfields[field]
- elif instnode.fromstart:
- fieldnode = InstanceNode(fromstart=True)
- instnode.add_escape_dependency(fieldnode)
- if instnode.origfields is None:
- instnode.origfields = {}
- instnode.origfields[field] = fieldnode
- else:
- return # nothing to be gained from tracking the field
- self.nodes[op.result] = fieldnode
-
- find_nodes_GETFIELD_GC_PURE = find_nodes_GETFIELD_GC
-
- def find_nodes_SETARRAYITEM_GC(self, op):
- indexbox = op.getarg(1)
- indexbox = self.get_constant_box(indexbox)
- if indexbox is None:
- self.find_nodes_default(op) # not a Const index
- return
- arraynode = self.getnode(op.getarg(0))
- itemnode = self.getnode(op.getarg(2))
- if arraynode.escaped:
- itemnode.mark_escaped()
- return # nothing to be gained from tracking the item
- if arraynode.curitems is None:
- arraynode.curitems = {}
- arraynode.curitems[indexbox.getint()] = itemnode
- arraynode.add_escape_dependency(itemnode)
-
- def find_nodes_GETARRAYITEM_GC(self, op):
- indexbox = op.getarg(1)
- indexbox = self.get_constant_box(indexbox)
- if indexbox is None:
- self.find_nodes_default(op) # not a Const index
- return
- arraynode = self.getnode(op.getarg(0))
- if arraynode.escaped:
- return # nothing to be gained from tracking the item
- index = indexbox.getint()
- if arraynode.curitems is not None and index in arraynode.curitems:
- itemnode = arraynode.curitems[index]
- elif arraynode.origitems is not None and index in arraynode.origitems:
- itemnode = arraynode.origitems[index]
- elif arraynode.fromstart:
- itemnode = InstanceNode(fromstart=True)
- arraynode.add_escape_dependency(itemnode)
- if arraynode.origitems is None:
- arraynode.origitems = {}
- arraynode.origitems[index] = itemnode
- else:
- return # nothing to be gained from tracking the item
- self.nodes[op.result] = itemnode
-
- find_nodes_GETARRAYITEM_GC_PURE = find_nodes_GETARRAYITEM_GC
-
- def find_nodes_JUMP(self, op):
- # only set up the 'unique' field of the InstanceNodes;
- # real handling comes later (build_result_specnodes() for loops).
- for i in range(op.numargs()):
- box = op.getarg(i)
- self.getnode(box).set_unique_nodes()
-
- def find_nodes_FINISH(self, op):
- # only for bridges, and only for the ones that end in a 'return'
- # or 'raise'; all other cases end with a JUMP.
- for i in range(op.numargs()):
- box = op.getarg(i)
- self.getnode(box).unique = UNIQUE_NO
-
-find_nodes_ops = _findall(NodeFinder, 'find_nodes_')
-
-# ____________________________________________________________
-# Perfect specialization -- for loops only
-
-class PerfectSpecializationFinder(NodeFinder):
- node_fromstart = InstanceNode(fromstart=True)
-
- def find_nodes_loop(self, loop, build_specnodes=True):
- self._loop = loop
- self.setup_input_nodes(loop.inputargs)
- self.find_nodes(loop.operations)
- if build_specnodes:
- self.build_result_specnodes(loop)
-
- def show(self):
- from pypy.jit.metainterp.viewnode import viewnodes, view
- op = self._loop.operations[-1]
- assert op.getopnum() == rop.JUMP
- exitnodes = [self.getnode(arg) for arg in op.args]
- viewnodes(self.inputnodes, exitnodes)
- if hasattr(self._loop.token, "specnodes"):
- view(*self._loop.token.specnodes)
-
-
- def setup_input_nodes(self, inputargs):
- inputnodes = []
- for box in inputargs:
- instnode = InstanceNode(fromstart=True)
- inputnodes.append(instnode)
- self.nodes[box] = instnode
- self.inputnodes = inputnodes
-
- def build_result_specnodes(self, loop):
- # Build the list of specnodes based on the result
- # computed by NodeFinder.find_nodes().
- op = loop.operations[-1]
- assert op.getopnum() == rop.JUMP
- assert len(self.inputnodes) == op.numargs()
- while True:
- self.restart_needed = False
- specnodes = []
- for i in range(op.numargs()):
- inputnode = self.inputnodes[i]
- exitnode = self.getnode(op.getarg(i))
- specnodes.append(self.intersect(inputnode, exitnode))
- if not self.restart_needed:
- break
- loop.token.specnodes = specnodes
-
- def intersect(self, inputnode, exitnode):
- assert inputnode.fromstart
- if inputnode.is_constant() and \
- exitnode.is_constant():
- if inputnode.knownvaluebox.same_constant(exitnode.knownvaluebox):
- return ConstantSpecNode(inputnode.knownvaluebox)
- else:
- raise InvalidLoop
- if inputnode.escaped:
- return prebuiltNotSpecNode
- unique = exitnode.unique
- if unique == UNIQUE_NO:
- if inputnode is not self.node_fromstart:
- # Mark the input node as escaped, and schedule a complete
- # restart of intersect(). This is needed because there is
- # an order dependency: calling inputnode.mark_escaped()
- # might set the field exitnode.unique to UNIQUE_NO in some
- # other node. If inputnode is node_fromstart, there is no
- # problem (and it must not be mutated by mark_escaped() then).
- inputnode.mark_escaped()
- self.restart_needed = True
- return prebuiltNotSpecNode
- if unique == UNIQUE_INST:
- return self.intersect_instance(inputnode, exitnode)
- if unique == UNIQUE_ARRAY:
- return self.intersect_array(inputnode, exitnode)
- if unique == UNIQUE_STRUCT:
- return self.intersect_struct(inputnode, exitnode)
- assert 0, "unknown value for exitnode.unique: %d" % ord(unique)
-
- def compute_common_fields(self, orig, d):
- fields = []
- if orig is not None:
- if d is not None:
- d = d.copy()
- else:
- d = {}
- for ofs in orig:
- d.setdefault(ofs, self.node_escaped)
- if d is not None:
- lst = d.keys()
- # we always use the "standardized" order of fields
- sort_descrs(lst)
- for ofs in lst:
- try:
- if orig is None:
- raise KeyError
- node = orig[ofs]
- except KeyError:
- # field stored at exit, but not read at input. Must
- # still be allocated, otherwise it will be incorrectly
- # uninitialized after a guard failure.
- node = self.node_fromstart
- specnode = self.intersect(node, d[ofs])
- fields.append((ofs, specnode))
- return fields
-
- def intersect_instance(self, inputnode, exitnode):
- if (inputnode.knownclsbox is not None and
- not inputnode.knownclsbox.same_constant(exitnode.knownclsbox)):
- # unique match, but the class is known to be a mismatch
- raise InvalidLoop
- #
- fields = self.compute_common_fields(inputnode.origfields,
- exitnode.curfields)
- return VirtualInstanceSpecNode(exitnode.knownclsbox, fields)
-
- def intersect_array(self, inputnode, exitnode):
- assert inputnode.arraydescr is None
- #
- items = []
- for i in range(exitnode.arraysize):
- if exitnode.curitems is None:
- exitsubnode = self.node_escaped
- else:
- exitsubnode = exitnode.curitems.get(i, self.node_escaped)
- if inputnode.origitems is None:
- node = self.node_fromstart
- else:
- node = inputnode.origitems.get(i, self.node_fromstart)
- specnode = self.intersect(node, exitsubnode)
- items.append(specnode)
- return VirtualArraySpecNode(exitnode.arraydescr, items)
-
- def intersect_struct(self, inputnode, exitnode):
- assert inputnode.structdescr is None
- #
- fields = self.compute_common_fields(inputnode.origfields,
- exitnode.curfields)
- return VirtualStructSpecNode(exitnode.structdescr, fields)
-
-# ____________________________________________________________
-# A subclass of NodeFinder for bridges only
-
-class __extend__(SpecNode):
- def make_instance_node(self):
- raise NotImplementedError
- def matches_instance_node(self, exitnode):
- raise NotImplementedError
-
-class __extend__(NotSpecNode):
- def make_instance_node(self):
- return NodeFinder.node_escaped
- def matches_instance_node(self, exitnode):
- return True
-
-class __extend__(ConstantSpecNode):
- def make_instance_node(self):
- raise AssertionError, "not implemented (but not used actually)"
- def matches_instance_node(self, exitnode):
- if exitnode.knownvaluebox is None:
- return False
- return self.constbox.same_constant(exitnode.knownvaluebox)
-
-class __extend__(VirtualInstanceSpecNode):
- def make_instance_node(self):
- instnode = InstanceNode()
- instnode.knownclsbox = self.known_class
- instnode.curfields = {}
- for ofs, subspecnode in self.fields:
- instnode.curfields[ofs] = subspecnode.make_instance_node()
- return instnode
-
- def matches_instance_node(self, exitnode):
- if exitnode.unique == UNIQUE_NO:
- return False
- #
- assert exitnode.unique == UNIQUE_INST
- if not self.known_class.same_constant(exitnode.knownclsbox):
- # unique match, but the class is known to be a mismatch
- return False
- #
- return matches_fields(self.fields, exitnode.curfields)
-
-def matches_fields(fields, d):
- seen = 0
- for ofs, subspecnode in fields:
- try:
- if d is None:
- raise KeyError
- instnode = d[ofs]
- seen += 1
- except KeyError:
- instnode = NodeFinder.node_escaped
- if not subspecnode.matches_instance_node(instnode):
- return False
- if d is not None and len(d) > seen:
- return False # some key is in d but not in fields
- return True
-
-class __extend__(VirtualArraySpecNode):
- def make_instance_node(self):
- raise AssertionError, "not implemented (but not used actually)"
- def matches_instance_node(self, exitnode):
- if exitnode.unique == UNIQUE_NO:
- return False
- #
- assert exitnode.unique == UNIQUE_ARRAY
- assert self.arraydescr == exitnode.arraydescr
- if len(self.items) != exitnode.arraysize:
- # the size is known to be a mismatch
- return False
- #
- d = exitnode.curitems
- for i in range(exitnode.arraysize):
- try:
- if d is None:
- raise KeyError
- itemnode = d[i]
- except KeyError:
- itemnode = NodeFinder.node_escaped
- subspecnode = self.items[i]
- if not subspecnode.matches_instance_node(itemnode):
- return False
- return True
-
-class __extend__(VirtualStructSpecNode):
- def make_instance_node(self):
- raise AssertionError, "not implemented (but not used actually)"
- def matches_instance_node(self, exitnode):
- if exitnode.unique == UNIQUE_NO:
- return False
- #
- assert exitnode.unique == UNIQUE_STRUCT
- assert self.typedescr == exitnode.structdescr
- #
- return matches_fields(self.fields, exitnode.curfields)
-
-
-class BridgeSpecializationFinder(NodeFinder):
-
- def find_nodes_bridge(self, bridge, specnodes=None):
- if specnodes is not None: # not used actually
- self.setup_bridge_input_nodes(specnodes, bridge.inputargs)
- self.find_nodes(bridge.operations)
- self.jump_op = bridge.operations[-1]
-
- def setup_bridge_input_nodes(self, specnodes, inputargs):
- assert len(specnodes) == len(inputargs)
- for i in range(len(inputargs)):
- instnode = specnodes[i].make_instance_node()
- box = inputargs[i]
- self.nodes[box] = instnode
-
- def bridge_matches(self, nextloop_specnodes):
- jump_op = self.jump_op
- assert jump_op.numargs() == len(nextloop_specnodes)
- for i in range(len(nextloop_specnodes)):
- exitnode = self.getnode(jump_op.getarg(i))
- if not nextloop_specnodes[i].matches_instance_node(exitnode):
- return False
- return True
diff --git a/pypy/jit/metainterp/test/test_specnode.py b/pypy/jit/metainterp/test/test_specnode.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_specnode.py
+++ /dev/null
@@ -1,132 +0,0 @@
-from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.jit.metainterp.history import AbstractDescr, BoxPtr, ConstInt, ConstPtr
-from pypy.jit.metainterp.specnode import prebuiltNotSpecNode
-from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
-from pypy.jit.metainterp.specnode import VirtualArraySpecNode
-from pypy.jit.metainterp.specnode import VirtualStructSpecNode
-from pypy.jit.metainterp.specnode import ConstantSpecNode
-from pypy.jit.metainterp.specnode import equals_specnodes
-from pypy.jit.metainterp.specnode import more_general_specnodes
-from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin
-
-def _get_vspecnode(classnum=123):
- return VirtualInstanceSpecNode(ConstInt(classnum),
- [(LLtypeMixin.valuedescr, prebuiltNotSpecNode),
- (LLtypeMixin.nextdescr, prebuiltNotSpecNode)])
-
-def _get_aspecnode(length=2):
- return VirtualArraySpecNode(LLtypeMixin.arraydescr,
- [prebuiltNotSpecNode] * length)
-
-def _get_sspecnode():
- return VirtualStructSpecNode(LLtypeMixin.ssize,
- [(LLtypeMixin.adescr, prebuiltNotSpecNode),
- (LLtypeMixin.bdescr, prebuiltNotSpecNode)])
-
-def _get_cspecnode(s):
- from pypy.rpython.module.support import LLSupport
- llstr = lltype.cast_opaque_ptr(llmemory.GCREF, LLSupport.to_rstr(s))
- box = ConstPtr(llstr)
- return ConstantSpecNode(box)
-
-def test_equals_specnodes():
- assert equals_specnodes([prebuiltNotSpecNode, prebuiltNotSpecNode],
- [prebuiltNotSpecNode, prebuiltNotSpecNode])
- vspecnode1 = _get_vspecnode(1)
- vspecnode2 = _get_vspecnode(2)
- assert equals_specnodes([vspecnode1], [vspecnode1])
- assert not equals_specnodes([vspecnode1], [vspecnode2])
- assert not equals_specnodes([vspecnode1], [prebuiltNotSpecNode])
- assert not equals_specnodes([prebuiltNotSpecNode], [vspecnode2])
- aspecnode1 = _get_aspecnode(1)
- aspecnode2 = _get_aspecnode(2)
- assert equals_specnodes([aspecnode2], [aspecnode2])
- assert not equals_specnodes([aspecnode1], [aspecnode2])
- assert not equals_specnodes([aspecnode1], [prebuiltNotSpecNode])
- assert not equals_specnodes([prebuiltNotSpecNode], [aspecnode2])
- sspecnode1 = _get_sspecnode()
- assert equals_specnodes([sspecnode1], [sspecnode1])
- assert not equals_specnodes([sspecnode1], [prebuiltNotSpecNode])
- assert not equals_specnodes([prebuiltNotSpecNode], [sspecnode1])
- #
- foonode = _get_cspecnode('foo')
- barnode = _get_cspecnode('bar')
- assert equals_specnodes([foonode], [foonode])
- assert not equals_specnodes([foonode], [barnode])
- assert not equals_specnodes([foonode], [prebuiltNotSpecNode])
-
-def test_more_general_specnodes():
- assert more_general_specnodes([prebuiltNotSpecNode, prebuiltNotSpecNode],
- [prebuiltNotSpecNode, prebuiltNotSpecNode])
- vspecnode1 = _get_vspecnode(1)
- vspecnode2 = _get_vspecnode(2)
- assert more_general_specnodes([vspecnode1], [vspecnode1])
- assert not more_general_specnodes([vspecnode1], [vspecnode2])
- assert not more_general_specnodes([vspecnode1], [prebuiltNotSpecNode])
- assert more_general_specnodes([prebuiltNotSpecNode], [vspecnode2])
- aspecnode1 = _get_aspecnode(1)
- aspecnode2 = _get_aspecnode(2)
- assert more_general_specnodes([aspecnode2], [aspecnode2])
- assert not more_general_specnodes([aspecnode1], [aspecnode2])
- assert not more_general_specnodes([aspecnode1], [prebuiltNotSpecNode])
- assert more_general_specnodes([prebuiltNotSpecNode], [aspecnode2])
- sspecnode1 = _get_sspecnode()
- assert more_general_specnodes([sspecnode1], [sspecnode1])
- assert not more_general_specnodes([sspecnode1], [prebuiltNotSpecNode])
- assert more_general_specnodes([prebuiltNotSpecNode], [sspecnode1])
- #
- foonode = _get_cspecnode('foo')
- barnode = _get_cspecnode('bar')
- assert more_general_specnodes([foonode], [foonode])
- assert not more_general_specnodes([foonode], [barnode])
- assert not more_general_specnodes([foonode], [prebuiltNotSpecNode])
- assert more_general_specnodes([prebuiltNotSpecNode], [foonode])
-
-def test_extract_runtime_data_0():
- res = []
- node = _get_cspecnode('foo')
- node.extract_runtime_data("cpu", "box1", res)
- assert res == []
-
-def test_extract_runtime_data_1():
- res = []
- prebuiltNotSpecNode.extract_runtime_data("cpu", "box1", res)
- prebuiltNotSpecNode.extract_runtime_data("cpu", "box2", res)
- assert res == ["box1", "box2"]
-
-def test_extract_runtime_data_2():
- structure = lltype.malloc(LLtypeMixin.NODE)
- structure.value = 515
- structure.next = lltype.malloc(LLtypeMixin.NODE)
- structbox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, structure))
- vspecnode = _get_vspecnode()
- res = []
- vspecnode.extract_runtime_data(LLtypeMixin.cpu, structbox, res)
- assert len(res) == 2
- assert res[0].value == structure.value
- assert res[1].value._obj.container._as_ptr() == structure.next
-
-def test_extract_runtime_data_3():
- array = lltype.malloc(lltype.GcArray(lltype.Signed), 2)
- array[0] = 123
- array[1] = 456
- arraybox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, array))
- aspecnode = _get_aspecnode()
- res = []
- aspecnode.extract_runtime_data(LLtypeMixin.cpu, arraybox, res)
- assert len(res) == 2
- assert res[0].value == 123
- assert res[1].value == 456
-
-def test_extract_runtime_data_4():
- struct = lltype.malloc(LLtypeMixin.S)
- struct.a = 123
- struct.b = lltype.malloc(LLtypeMixin.NODE)
- structbox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, struct))
- sspecnode = _get_sspecnode()
- res = []
- sspecnode.extract_runtime_data(LLtypeMixin.cpu, structbox, res)
- assert len(res) == 2
- assert res[0].value == 123
- assert (lltype.cast_opaque_ptr(lltype.Ptr(LLtypeMixin.NODE), res[1].value)
- == struct.b)
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
@@ -1,26 +1,19 @@
import py
from pypy.rlib.objectmodel import instantiate
-from pypy.jit.metainterp.test.test_optimizefindnode import (LLtypeMixin,
- #OOtypeMixin,
- BaseTest)
-from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder
+from pypy.jit.metainterp.test.test_optimizeutil import (LLtypeMixin,
+ #OOtypeMixin,
+ BaseTest)
import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt
import pypy.jit.metainterp.optimizeopt.virtualize as virtualize
from pypy.jit.metainterp.optimizeopt import optimize_loop_1
from pypy.jit.metainterp.optimizeutil import InvalidLoop
from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt
+from pypy.jit.metainterp.history import TreeLoop, LoopToken
from pypy.jit.metainterp.jitprof import EmptyProfiler
from pypy.jit.metainterp import executor, compile, resume, history
from pypy.jit.metainterp.resoperation import rop, opname, ResOperation
from pypy.jit.tool.oparser import pure_parse
-
-##class FakeFrame(object):
-## parent_resumedata_snapshot = None
-## parent_resumedata_frame_info_list = None
-
-## def __init__(self, code="", pc=0):
-## self.jitcode = code
-## self.pc = pc
+from pypy.jit.metainterp.test.test_optimizebasic import equaloplists
class Fake(object):
failargs_limit = 1000
@@ -129,90 +122,7 @@
assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()])
-
# ____________________________________________________________
-
-def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}):
- # try to use the full width of the terminal to display the list
- # unfortunately, does not work with the default capture method of py.test
- # (which is fd), you you need to use either -s or --capture=sys, else you
- # get the standard 80 columns width
- totwidth = py.io.get_terminal_width()
- width = totwidth / 2 - 1
- print ' Comparing lists '.center(totwidth, '-')
- print '%s| %s' % ('optimized'.center(width), 'expected'.center(width))
- for op1, op2 in zip(oplist1, oplist2):
- txt1 = str(op1)
- txt2 = str(op2)
- while txt1 or txt2:
- print '%s| %s' % (txt1[:width].ljust(width), txt2[:width])
- txt1 = txt1[width:]
- txt2 = txt2[width:]
- assert op1.getopnum() == op2.getopnum()
- assert op1.numargs() == op2.numargs()
- for i in range(op1.numargs()):
- x = op1.getarg(i)
- y = op2.getarg(i)
- assert x == remap.get(y, y)
- if op2.result in remap:
- assert op1.result == remap[op2.result]
- else:
- remap[op2.result] = op1.result
- if op1.getopnum() != rop.JUMP: # xxx obscure
- assert op1.getdescr() == op2.getdescr()
- if op1.getfailargs() or op2.getfailargs():
- assert len(op1.getfailargs()) == len(op2.getfailargs())
- if strict_fail_args:
- for x, y in zip(op1.getfailargs(), op2.getfailargs()):
- assert x == remap.get(y, y)
- else:
- fail_args1 = set(op1.getfailargs())
- fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()])
- assert fail_args1 == fail_args2
- assert len(oplist1) == len(oplist2)
- print '-'*57
- return True
-
-def test_equaloplists():
- ops = """
- [i0]
- i1 = int_add(i0, 1)
- i2 = int_add(i1, 1)
- guard_true(i1) [i2]
- jump(i1)
- """
- namespace = {}
- loop1 = pure_parse(ops, namespace=namespace)
- loop2 = pure_parse(ops, namespace=namespace)
- loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"),
- namespace=namespace)
- assert equaloplists(loop1.operations, loop2.operations)
- py.test.raises(AssertionError,
- "equaloplists(loop1.operations, loop3.operations)")
-
-def test_equaloplists_fail_args():
- ops = """
- [i0]
- i1 = int_add(i0, 1)
- i2 = int_add(i1, 1)
- guard_true(i1) [i2, i1]
- jump(i1)
- """
- namespace = {}
- loop1 = pure_parse(ops, namespace=namespace)
- loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"),
- namespace=namespace)
- py.test.raises(AssertionError,
- "equaloplists(loop1.operations, loop2.operations)")
- assert equaloplists(loop1.operations, loop2.operations,
- strict_fail_args=False)
- loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"),
- namespace=namespace)
- py.test.raises(AssertionError,
- "equaloplists(loop1.operations, loop3.operations)")
-
-# ____________________________________________________________
-
class Storage(compile.ResumeGuardDescr):
"for tests."
def __init__(self, metainterp_sd=None, original_greenkey=None):
@@ -222,6 +132,10 @@
op.setfailargs(boxes)
def __eq__(self, other):
return type(self) is type(other) # xxx obscure
+ def clone_if_mutable(self):
+ res = Storage(self.metainterp_sd, self.original_greenkey)
+ self.copy_all_attrbutes_into(res)
+ return res
def _sortboxes(boxes):
_kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3}
@@ -238,31 +152,25 @@
descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args))
return descr
- def assert_equal(self, optimized, expected):
+ def assert_equal(self, optimized, expected, text_right=None):
assert len(optimized.inputargs) == len(expected.inputargs)
remap = {}
for box1, box2 in zip(optimized.inputargs, expected.inputargs):
assert box1.__class__ == box2.__class__
remap[box2] = box1
assert equaloplists(optimized.operations,
- expected.operations, False, remap)
-
- def optimize_loop(self, ops, spectext, optops, checkspecnodes=True):
+ expected.operations, False, remap, text_right)
+
+ def optimize_loop(self, ops, optops, expected_preamble=None):
loop = self.parse(ops)
- #
- if checkspecnodes:
- # verify that 'spectext' is indeed what optimizefindnode would
- # compute for this loop
- cpu = self.cpu
- perfect_specialization_finder = PerfectSpecializationFinder(cpu)
- perfect_specialization_finder.find_nodes_loop(loop)
- self.check_specnodes(loop.token.specnodes, spectext)
- else:
- # for cases where we want to see how optimizeopt behaves with
- # combinations different from the one computed by optimizefindnode
- loop.token.specnodes = self.unpack_specnodes(spectext)
+ expected = self.parse(optops)
+ if expected_preamble:
+ expected_preamble = self.parse(expected_preamble)
#
self.loop = loop
+ loop.preamble = TreeLoop('preamble')
+ loop.preamble.inputargs = loop.inputargs
+ loop.preamble.token = LoopToken()
metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi)
if hasattr(self, 'vrefinfo'):
metainterp_sd.virtualref_info = self.vrefinfo
@@ -270,28 +178,70 @@
metainterp_sd.callinfocollection = self.callinfocollection
optimize_loop_1(metainterp_sd, loop)
#
- expected = self.parse(optops)
+
+ print
+ print loop.preamble.inputargs
+ print '\n'.join([str(o) for o in loop.preamble.operations])
+ print
+ print loop.inputargs
print '\n'.join([str(o) for o in loop.operations])
+ print
+
self.assert_equal(loop, expected)
+ if expected_preamble:
+ self.assert_equal(loop.preamble, expected_preamble,
+ text_right='expected preamble')
+
return loop
-
class OptimizeOptTest(BaseTestOptimizeOpt):
+ def setup_method(self, meth=None):
+ class FailDescr(compile.ResumeGuardDescr):
+ oparse = None
+ def _oparser_uses_descr_of_guard(self, oparse, fail_args):
+ # typically called 3 times: once when parsing 'ops',
+ # once when parsing 'preamble', once when parsing 'expected'.
+ self.oparse = oparse
+ self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args)
+ def _clone_if_mutable(self):
+ assert self is fdescr
+ return fdescr2
+ def __repr__(self):
+ if self is fdescr:
+ return 'fdescr'
+ if self is fdescr2:
+ return 'fdescr2'
+ return compile.ResumeGuardDescr.__repr__(self)
+ #
+ def snapshot(fail_args, got=[]):
+ if not got: # only the first time, i.e. when parsing 'ops'
+ rd_frame_info_list = resume.FrameInfo(None, "code", 11)
+ rd_snapshot = resume.Snapshot(None, fail_args)
+ got.append(rd_frame_info_list)
+ got.append(rd_snapshot)
+ return got
+ #
+ fdescr = instantiate(FailDescr)
+ self.namespace['fdescr'] = fdescr
+ fdescr2 = instantiate(FailDescr)
+ self.namespace['fdescr2'] = fdescr2
+
+ def teardown_method(self, meth):
+ self.namespace.pop('fdescr', None)
+ self.namespace.pop('fdescr2', None)
+
+
def test_simple(self):
ops = """
- [i]
- i0 = int_sub(i, 1)
- guard_value(i0, 0) [i0]
- jump(i)
- """
- expected = """
- [i]
- i0 = int_sub(i, 1)
- guard_value(i0, 0) [i0]
- jump(1)
- """
- self.optimize_loop(ops, 'Not', expected)
+ []
+ f = escape()
+ f0 = float_sub(f, 1.0)
+ guard_value(f0, 0.0) [f0]
+ escape(f)
+ jump()
+ """
+ self.optimize_loop(ops, ops)
def test_constant_propagate(self):
ops = """
@@ -308,7 +258,7 @@
[]
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_constant_propagate_ovf(self):
ops = """
@@ -326,7 +276,7 @@
[]
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_constfold_all(self):
from pypy.jit.backend.llgraph.llimpl import TYPES # xxx fish
@@ -360,7 +310,7 @@
escape(%d)
jump()
""" % expected_value
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
# ----------
@@ -371,12 +321,16 @@
guard_class(p0, ConstClass(node_vtable)) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
guard_class(p0, ConstClass(node_vtable)) []
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, expected_preamble=preamble)
def test_remove_guard_class_2(self):
ops = """
@@ -392,7 +346,7 @@
escape(p0)
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_remove_guard_class_constant(self):
ops = """
@@ -405,7 +359,7 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_constant_boolrewrite_lt(self):
ops = """
@@ -416,13 +370,17 @@
guard_false(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 0)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, expected_preamble=preamble)
def test_constant_boolrewrite_gt(self):
ops = """
@@ -433,13 +391,17 @@
guard_false(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_gt(i0, 0)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, expected_preamble=preamble)
def test_constant_boolrewrite_reflex(self):
ops = """
@@ -450,13 +412,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_gt(i0, 0)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, expected_preamble=preamble)
def test_constant_boolrewrite_reflex_invers(self):
ops = """
@@ -467,13 +433,17 @@
guard_false(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_gt(i0, 0)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, expected_preamble=preamble)
def test_remove_consecutive_guard_value_constfold(self):
ops = """
@@ -493,19 +463,19 @@
escape(3)
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_remove_guard_value_if_constant(self):
ops = """
[p1]
guard_value(p1, ConstPtr(myptr)) []
- jump(ConstPtr(myptr))
+ jump(p1)
"""
expected = """
[]
jump()
"""
- self.optimize_loop(ops, 'Constant(myptr)', expected)
+ self.optimize_loop(ops, expected)
def test_ooisnull_oononnull_1(self):
ops = """
@@ -514,12 +484,52 @@
guard_nonnull(p0) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
guard_class(p0, ConstClass(node_vtable)) []
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_guard_nonnull_class_1(self):
+ ops = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ guard_nonnull(p0) []
+ guard_nonnull_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ preamble = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_guard_nonnull_class_2(self):
+ ops = """
+ [p0]
+ guard_nonnull_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ preamble = """
+ [p0]
+ guard_nonnull_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_int_is_true_1(self):
ops = """
@@ -530,13 +540,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_is_true(i0)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_int_is_true_is_zero(self):
py.test.skip("XXX implement me")
@@ -554,7 +568,7 @@
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_ooisnull_oononnull_2(self):
ops = """
@@ -563,12 +577,16 @@
guard_nonnull(p0) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
guard_nonnull(p0) []
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_ooisnull_on_null_ptr_1(self):
ops = """
@@ -584,7 +602,7 @@
guard_isnull(p0) []
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_ooisnull_oononnull_via_virtual(self):
ops = """
@@ -596,12 +614,16 @@
guard_nonnull(p1) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
guard_nonnull(p0) []
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_oois_1(self):
ops = """
@@ -617,12 +639,16 @@
guard_false(i1) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
guard_class(p0, ConstClass(node_vtable)) []
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_nonnull_1(self):
ops = """
@@ -644,7 +670,7 @@
setfield_gc(p0, 5, descr=valuedescr)
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_const_guard_value(self):
ops = """
@@ -657,7 +683,7 @@
[]
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_constptr_guard_value(self):
ops = """
@@ -666,7 +692,7 @@
guard_value(p1, ConstPtr(myptr)) []
jump()
"""
- self.optimize_loop(ops, '', ops)
+ self.optimize_loop(ops, ops)
def test_guard_value_to_guard_true(self):
ops = """
@@ -675,13 +701,17 @@
guard_value(i1, 1) [i]
jump(i)
"""
- expected = """
+ preamble = """
[i]
i1 = int_lt(i, 3)
guard_true(i1) [i]
jump(i)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i]
+ jump(i)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_guard_value_to_guard_false(self):
ops = """
@@ -690,13 +720,17 @@
guard_value(i1, 0) [i]
jump(i)
"""
- expected = """
+ preamble = """
[i]
i1 = int_is_true(i)
guard_false(i1) [i]
jump(i)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i]
+ jump(i)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_guard_value_on_nonbool(self):
ops = """
@@ -705,13 +739,17 @@
guard_value(i1, 0) [i]
jump(i)
"""
- expected = """
+ preamble = """
[i]
i1 = int_add(i, 3)
guard_value(i1, 0) [i]
- jump(-3)
- """
- self.optimize_loop(ops, 'Not', expected)
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_int_is_true_of_bool(self):
ops = """
@@ -722,13 +760,17 @@
guard_value(i4, 0) [i0, i1]
jump(i0, i1)
"""
- expected = """
+ preamble = """
[i0, i1]
i2 = int_gt(i0, i1)
guard_false(i2) [i0, i1]
jump(i0, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ expected = """
+ [i0, i1]
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
@@ -742,8 +784,22 @@
setfield_gc(p1, i1, descr=valuedescr)
jump(i1, p1, p2)
"""
+ preamble = """
+ [i1, p2, p3]
+ i3 = getfield_gc(p3, descr=valuedescr)
+ escape(i3)
+ jump(i1, p2)
+ """
+ expected = """
+ [i1, p2]
+ i3 = getfield_gc(p2, descr=valuedescr)
+ escape(i3)
+ p3 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p3, i1, descr=valuedescr)
+ jump(i1, p3)
+ """
# We cannot track virtuals that survive for more than two iterations.
- self.optimize_loop(ops, 'Not, Not, Not', ops)
+ self.optimize_loop(ops, expected, preamble)
def test_p123_nested(self):
ops = """
@@ -759,7 +815,24 @@
"""
# The same as test_p123_simple, but with a virtual containing another
# virtual.
- self.optimize_loop(ops, 'Not, Not, Not', ops)
+ preamble = """
+ [i1, p2, p3]
+ i3 = getfield_gc(p3, descr=valuedescr)
+ escape(i3)
+ jump(i1, p2)
+ """
+ expected = """
+ [i1, p2]
+ i3 = getfield_gc(p2, descr=valuedescr)
+ escape(i3)
+ p4 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p4, i1, descr=valuedescr)
+ p1sub = new_with_vtable(ConstClass(node_vtable2))
+ setfield_gc(p1sub, i1, descr=valuedescr)
+ setfield_gc(p4, p1sub, descr=nextdescr)
+ jump(i1, p4)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_p123_anti_nested(self):
ops = """
@@ -775,7 +848,58 @@
"""
# The same as test_p123_simple, but in the end the "old" p2 contains
# a "young" virtual p2sub. Make sure it is all forced.
- self.optimize_loop(ops, 'Not, Not, Not', ops)
+ preamble = """
+ [i1, p2, p3]
+ p3sub = getfield_gc(p3, descr=nextdescr)
+ i3 = getfield_gc(p3sub, descr=valuedescr)
+ escape(i3)
+ p2sub = new_with_vtable(ConstClass(node_vtable2))
+ setfield_gc(p2sub, i1, descr=valuedescr)
+ setfield_gc(p2, p2sub, descr=nextdescr)
+ jump(i1, p2, p2sub)
+ """
+ expected = """
+ [i1, p2, p2sub]
+ i3 = getfield_gc(p2sub, descr=valuedescr)
+ escape(i3)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p3sub = new_with_vtable(ConstClass(node_vtable2))
+ setfield_gc(p3sub, i1, descr=valuedescr)
+ setfield_gc(p1, p3sub, descr=nextdescr)
+ jump(i1, p1, p3sub)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_dont_delay_setfields(self):
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=nextdescr)
+ i2 = int_sub(i1, 1)
+ i2b = int_is_true(i2)
+ guard_true(i2b) []
+ setfield_gc(p2, i2, descr=nextdescr)
+ p3 = new_with_vtable(ConstClass(node_vtable))
+ jump(p2, p3)
+ """
+ preamble = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=nextdescr)
+ i2 = int_sub(i1, 1)
+ i2b = int_is_true(i2)
+ guard_true(i2b) []
+ setfield_gc(p2, i2, descr=nextdescr)
+ jump(p2, i2)
+ """
+ expected = """
+ [p2, i1]
+ i2 = int_sub(i1, 1)
+ i2b = int_is_true(i2)
+ guard_true(i2b) []
+ p3 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p3, i2, descr=nextdescr)
+ jump(p3, i2)
+ """
+ self.optimize_loop(ops, expected, preamble)
# ----------
@@ -794,7 +918,7 @@
# note that 'guard_no_exception' at the very start must be kept
# around: bridges may start with one. (In case of loops we could
# remove it, but we probably don't care.)
- expected = """
+ preamble = """
[i]
guard_no_exception() []
i1 = int_add(i, 3)
@@ -803,7 +927,15 @@
i3 = call(i2, descr=nonwritedescr)
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i]
+ i1 = int_add(i, 3)
+ i2 = call(i1, descr=nonwritedescr)
+ guard_no_exception() [i1, i2]
+ i3 = call(i2, descr=nonwritedescr)
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
# ----------
@@ -821,14 +953,18 @@
guard_value(i4, 1) []
jump(i1)
"""
- expected = """
+ preamble = """
[i1]
i2 = call(1, i1, descr=nonwritedescr)
guard_no_exception() []
guard_value(i2, 1) []
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i1]
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
# ----------
@@ -838,49 +974,44 @@
[i, p0]
i0 = getfield_gc(p0, descr=valuedescr)
i1 = int_add(i0, i)
- setfield_gc(p0, i1, descr=valuedescr)
- jump(i, p0)
- """
- expected = """
- [i, i2]
- i1 = int_add(i2, i)
- jump(i, i1)
- """
- self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
- expected, checkspecnodes=False)
-
- def test_virtual_float(self):
- ops = """
- [f, p0]
- f0 = getfield_gc(p0, descr=floatdescr)
- f1 = float_add(f0, f)
- setfield_gc(p0, f1, descr=floatdescr)
- jump(f, p0)
- """
- expected = """
- [f, f2]
- f1 = float_add(f2, f)
- jump(f, f1)
- """
- self.optimize_loop(ops, 'Not, Virtual(node_vtable, floatdescr=Not)',
- expected, checkspecnodes=False)
-
- def test_virtual_2(self):
- ops = """
- [i, p0]
- i0 = getfield_gc(p0, descr=valuedescr)
- i1 = int_add(i0, i)
p1 = new_with_vtable(ConstClass(node_vtable))
setfield_gc(p1, i1, descr=valuedescr)
jump(i, p1)
"""
+ preamble = """
+ [i, p0]
+ i0 = getfield_gc(p0, descr=valuedescr)
+ i1 = int_add(i0, i)
+ jump(i, i1)
+ """
expected = """
[i, i2]
i1 = int_add(i2, i)
jump(i, i1)
"""
- self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
- expected)
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_virtual_float(self):
+ ops = """
+ [f, p0]
+ f0 = getfield_gc(p0, descr=floatdescr)
+ f1 = float_add(f0, f)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, f1, descr=floatdescr)
+ jump(f, p1)
+ """
+ preamble = """
+ [f, p0]
+ f2 = getfield_gc(p0, descr=floatdescr)
+ f1 = float_add(f2, f)
+ jump(f, f1)
+ """
+ expected = """
+ [f, f2]
+ f1 = float_add(f2, f)
+ jump(f, f1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_virtual_oois(self):
ops = """
@@ -909,14 +1040,10 @@
jump(p0, p1, p2)
"""
expected = """
- [p2]
+ [p0, p1, p2]
# all constant-folded :-)
- jump(p2)
- """
- self.optimize_loop(ops, '''Virtual(node_vtable),
- Virtual(node_vtable),
- Not''',
- expected, checkspecnodes=False)
+ jump(p0, p1, p2)
+ """
#
# to be complete, we also check the no-opt case where most comparisons
# are not removed. The exact set of comparisons removed depends on
@@ -932,7 +1059,7 @@
guard_true(i11) []
jump(p0, p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected2)
+ self.optimize_loop(ops, expected, expected2)
def test_virtual_default_field(self):
ops = """
@@ -943,15 +1070,17 @@
# the field 'value' has its default value of 0
jump(p1)
"""
- expected = """
- [i]
- guard_value(i, 0) []
- jump(0)
- """
- # the 'expected' is sub-optimal, but it should be done by another later
- # optimization step. See test_find_nodes_default_field() for why.
- self.optimize_loop(ops, 'Virtual(node_vtable, valuedescr=Not)',
- expected)
+ preamble = """
+ [p0]
+ i0 = getfield_gc(p0, descr=valuedescr)
+ guard_value(i0, 0) []
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_virtual_3(self):
ops = """
@@ -967,7 +1096,7 @@
i1 = int_add(i, 1)
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_virtual_4(self):
ops = """
@@ -980,14 +1109,21 @@
setfield_gc(p1, i2, descr=valuedescr)
jump(i3, p1)
"""
+ preamble = """
+ [i0, p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ i1 = getfield_gc(p0, descr=valuedescr)
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i0, i1)
+ jump(i3, i2)
+ """
expected = """
[i0, i1]
i2 = int_sub(i1, 1)
i3 = int_add(i0, i1)
jump(i3, i2)
"""
- self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
- expected)
+ self.optimize_loop(ops, expected, preamble)
def test_virtual_5(self):
ops = """
@@ -1003,18 +1139,21 @@
setfield_gc(p1, p2, descr=nextdescr)
jump(i3, p1)
"""
+ preamble = """
+ [i0, p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ i1 = getfield_gc(p0, descr=valuedescr)
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i0, i1)
+ jump(i3, i2, i1)
+ """
expected = """
[i0, i1, i1bis]
i2 = int_sub(i1, 1)
i3 = int_add(i0, i1)
jump(i3, i2, i1)
"""
- self.optimize_loop(ops,
- '''Not, Virtual(node_vtable,
- valuedescr=Not,
- nextdescr=Virtual(node_vtable2,
- valuedescr=Not))''',
- expected)
+ self.optimize_loop(ops, expected, preamble)
def test_virtual_constant_isnull(self):
ops = """
@@ -1025,11 +1164,15 @@
i1 = ptr_eq(p2, NULL)
jump(i1)
"""
- expected = """
+ preamble = """
[i0]
- jump(1)
- """
- self.optimize_loop(ops, 'Not', expected)
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_virtual_constant_isnonnull(self):
@@ -1041,11 +1184,15 @@
i1 = ptr_eq(p2, NULL)
jump(i1)
"""
- expected = """
+ preamble = """
[i0]
- jump(0)
- """
- self.optimize_loop(ops, 'Not', expected)
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected)
def test_nonvirtual_1(self):
ops = """
@@ -1067,7 +1214,7 @@
escape(p1)
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_nonvirtual_2(self):
ops = """
@@ -1079,8 +1226,22 @@
setfield_gc(p1, i1, descr=valuedescr)
jump(i, p1)
"""
- expected = ops
- self.optimize_loop(ops, 'Not, Not', expected)
+ preamble = """
+ [i, p0]
+ i0 = getfield_gc(p0, descr=valuedescr)
+ escape(p0)
+ i1 = int_add(i0, i)
+ jump(i, i1)
+ """
+ expected = """
+ [i, i1]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i1, descr=valuedescr)
+ escape(p1)
+ i2 = int_add(i1, i)
+ jump(i, i2)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_nonvirtual_later(self):
ops = """
@@ -1102,7 +1263,7 @@
i3 = int_add(i, i2)
jump(i3)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_nonvirtual_dont_write_null_fields_on_force(self):
ops = """
@@ -1122,7 +1283,7 @@
i2 = getfield_gc(p1, descr=valuedescr)
jump(i2)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_getfield_gc_pure_1(self):
ops = """
@@ -1136,7 +1297,7 @@
[i]
jump(i)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_getfield_gc_pure_2(self):
ops = """
@@ -1145,11 +1306,11 @@
jump(i1)
"""
expected = """
- [i]
- jump(5)
+ []
+ jump()
"""
self.node.value = 5
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_getfield_gc_nonpure_2(self):
ops = """
@@ -1157,8 +1318,12 @@
i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
jump(i1)
"""
- expected = ops
- self.optimize_loop(ops, 'Not', expected)
+ preamble = ops
+ expected = """
+ [i]
+ jump(i)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_varray_1(self):
ops = """
@@ -1175,7 +1340,7 @@
[i1]
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_varray_alloc_and_set(self):
ops = """
@@ -1185,11 +1350,15 @@
i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
jump(i2)
"""
- expected = """
+ preamble = """
[i1]
- jump(0)
- """
- self.optimize_loop(ops, 'Not', expected)
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_varray_float(self):
ops = """
@@ -1206,7 +1375,7 @@
[f1]
jump(f1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_array_non_optimized(self):
ops = """
@@ -1222,7 +1391,7 @@
p1 = new_array(i1, descr=arraydescr)
jump(i1, p1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_nonvirtual_array_dont_write_null_fields_on_force(self):
ops = """
@@ -1240,7 +1409,7 @@
escape(p1)
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_varray_2(self):
ops = """
@@ -1254,13 +1423,21 @@
setarrayitem_gc(p2, 0, 20, descr=arraydescr)
jump(i0, p2)
"""
- expected = """
- [i0, i1, i2]
+ preamble = """
+ [i0, p1]
+ i1 = getarrayitem_gc(p1, 0, descr=arraydescr)
+ i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
i3 = int_sub(i1, i2)
guard_value(i3, 15) []
- jump(i0, 20, i0)
- """
- self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected)
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i3 = int_sub(20, i0)
+ guard_value(i3, 15) []
+ jump(5)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_p123_array(self):
ops = """
@@ -1271,8 +1448,22 @@
setarrayitem_gc(p1, 0, i1, descr=arraydescr)
jump(i1, p1, p2)
"""
+ preamble = """
+ [i1, p2, p3]
+ i3 = getarrayitem_gc(p3, 0, descr=arraydescr)
+ escape(i3)
+ jump(i1, p2)
+ """
+ expected = """
+ [i1, p2]
+ i3 = getarrayitem_gc(p2, 0, descr=arraydescr)
+ escape(i3)
+ p1 = new_array(1, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i1, descr=arraydescr)
+ jump(i1, p1)
+ """
# We cannot track virtuals that survive for more than two iterations.
- self.optimize_loop(ops, 'Not, Not, Not', ops)
+ self.optimize_loop(ops, expected, preamble)
def test_varray_forced_1(self):
ops = """
@@ -1294,7 +1485,7 @@
escape(i2)
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_vstruct_1(self):
ops = """
@@ -1305,12 +1496,18 @@
setfield_gc(p3, i1, descr=adescr)
jump(i1, p3)
"""
- expected = """
- [i1, i2]
+ preamble = """
+ [i1, p2]
+ i2 = getfield_gc(p2, descr=adescr)
escape(i2)
- jump(i1, i1)
- """
- self.optimize_loop(ops, 'Not, VStruct(ssize, adescr=Not)', expected)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ escape(i1)
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_p123_vstruct(self):
ops = """
@@ -1321,8 +1518,22 @@
setfield_gc(p1, i1, descr=adescr)
jump(i1, p1, p2)
"""
+ preamble = """
+ [i1, p2, p3]
+ i3 = getfield_gc(p3, descr=adescr)
+ escape(i3)
+ jump(i1, p2)
+ """
+ expected = """
+ [i1, p2]
+ i3 = getfield_gc(p2, descr=adescr)
+ escape(i3)
+ p1 = new(descr=ssize)
+ setfield_gc(p1, i1, descr=adescr)
+ jump(i1, p1)
+ """
# We cannot track virtuals that survive for more than two iterations.
- self.optimize_loop(ops, 'Not, Not, Not', ops)
+ self.optimize_loop(ops, expected, preamble)
def test_duplicate_getfield_1(self):
ops = """
@@ -1347,7 +1558,7 @@
escape(i2)
jump(p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_getfield_after_setfield(self):
ops = """
@@ -1363,7 +1574,7 @@
escape(i1)
jump(p1, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_setfield_of_different_type_does_not_clear(self):
ops = """
@@ -1381,7 +1592,7 @@
escape(i1)
jump(p1, p2, i1)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_setfield_of_same_type_clears(self):
ops = """
@@ -1392,7 +1603,7 @@
escape(i3)
jump(p1, p2, i1, i3)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_duplicate_getfield_mergepoint_has_no_side_effects(self):
ops = """
@@ -1412,7 +1623,7 @@
escape(i1)
jump(p1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getfield_ovf_op_does_not_clear(self):
ops = """
@@ -1434,7 +1645,7 @@
escape(i1)
jump(p1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getfield_setarrayitem_does_not_clear(self):
ops = """
@@ -1454,7 +1665,7 @@
escape(i1)
jump(p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getfield_constant(self):
ops = """
@@ -1472,7 +1683,7 @@
escape(i1)
jump()
"""
- self.optimize_loop(ops, '', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getfield_guard_value_const(self):
ops = """
@@ -1491,7 +1702,7 @@
escape(i1)
jump()
"""
- self.optimize_loop(ops, 'Constant(myptr)', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getfield_sideeffects_1(self):
ops = """
@@ -1503,7 +1714,7 @@
escape(i2)
jump(p1)
"""
- self.optimize_loop(ops, 'Not', ops)
+ self.optimize_loop(ops, ops)
def test_duplicate_getfield_sideeffects_2(self):
ops = """
@@ -1514,7 +1725,7 @@
escape(i2)
jump(p1, i1)
"""
- self.optimize_loop(ops, 'Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_duplicate_setfield_1(self):
ops = """
@@ -1528,7 +1739,7 @@
setfield_gc(p1, i2, descr=valuedescr)
jump(p1, i1, i2)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_setfield_2(self):
ops = """
@@ -1545,7 +1756,7 @@
escape(i1)
jump(p1, i1, i3)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_setfield_3(self):
ops = """
@@ -1558,7 +1769,7 @@
"""
# potential aliasing of p1 and p2 means that we cannot kill the
# the setfield_gc
- self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_duplicate_setfield_4(self):
ops = """
@@ -1575,7 +1786,7 @@
setfield_gc(p1, i2, descr=valuedescr)
jump(p1, i1, i2, p3)
"""
- expected = """
+ preamble = """
[p1, i1, i2, p3]
#
i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
@@ -1585,9 +1796,20 @@
#
setfield_gc(p1, i2, descr=valuedescr)
setfield_gc(p1, i4, descr=nextdescr)
- jump(p1, i1, i2, p3)
- """
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+ jump(p1, i1, i2, p3, i3)
+ """
+ expected = """
+ [p1, i1, i2, p3, i3]
+ #
+ i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+ i5 = int_add(i3, i4)
+ setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+ #
+ setfield_gc(p1, i2, descr=valuedescr)
+ setfield_gc(p1, i4, descr=nextdescr)
+ jump(p1, i1, i2, p3, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_duplicate_setfield_5(self):
ops = """
@@ -1609,7 +1831,7 @@
escape(i1)
jump(p0, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_setfield_sideeffects_1(self):
ops = """
@@ -1619,7 +1841,7 @@
setfield_gc(p1, i2, descr=valuedescr)
jump(p1, i1, i2)
"""
- self.optimize_loop(ops, 'Not, Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_duplicate_setfield_residual_guard_1(self):
ops = """
@@ -1630,7 +1852,22 @@
setfield_gc(p1, i2, descr=valuedescr)
jump(p1, i1, i2, i4)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+ preamble = """
+ [p1, i1, i2, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ guard_true(i3) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, i4)
+ """
+ expected = """
+ [p1, i1, i2, i4]
+ setfield_gc(p1, i1, descr=valuedescr)
+ guard_true(i4) []
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, 1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_duplicate_setfield_residual_guard_2(self):
# the difference with the previous test is that the field value is
@@ -1644,14 +1881,20 @@
setfield_gc(p1, NULL, descr=nextdescr)
jump(p1, i2, i4)
"""
- expected = """
+ preamble = """
[p1, i2, i3]
guard_true(i3) [p1]
i4 = int_neg(i2)
setfield_gc(p1, NULL, descr=nextdescr)
jump(p1, i2, i4)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ expected = """
+ [p1, i2, i4]
+ guard_true(i4) [p1]
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, 1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_duplicate_setfield_residual_guard_3(self):
ops = """
@@ -1664,14 +1907,20 @@
setfield_gc(p1, NULL, descr=nextdescr)
jump(p1, i2, i4)
"""
- expected = """
+ preamble = """
[p1, i2, i3]
guard_true(i3) [i2, p1]
i4 = int_neg(i2)
setfield_gc(p1, NULL, descr=nextdescr)
jump(p1, i2, i4)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ expected = """
+ [p1, i2, i4]
+ guard_true(i4) [i2, p1]
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, 1)
+ """
+ self.optimize_loop(ops, expected)
def test_duplicate_setfield_residual_guard_4(self):
# test that the setfield_gc does not end up between int_eq and
@@ -1685,7 +1934,16 @@
setfield_gc(p1, i2, descr=valuedescr)
jump(p1, i1, i2, i4)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+ preamble = ops
+ expected = """
+ [p1, i1, i2, i4]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i5 = int_eq(i4, 5)
+ guard_true(i5) []
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, 5)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_duplicate_setfield_aliasing(self):
# a case where aliasing issues (and not enough cleverness) mean
@@ -1697,7 +1955,7 @@
setfield_gc(p1, i3, descr=valuedescr)
jump(p1, p2, i1, i2, i3)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_duplicate_setfield_guard_value_const(self):
ops = """
@@ -1712,7 +1970,7 @@
setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
jump(i1, i2)
"""
- self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getarrayitem_1(self):
ops = """
@@ -1737,7 +1995,7 @@
escape(p3)
jump(p1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getarrayitem_after_setarrayitem_1(self):
ops = """
@@ -1753,7 +2011,7 @@
escape(p2)
jump(p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getarrayitem_after_setarrayitem_2(self):
ops = """
@@ -1775,7 +2033,7 @@
escape(p3)
jump(p1, p2, p3, i1)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getarrayitem_after_setarrayitem_3(self):
ops = """
@@ -1802,7 +2060,7 @@
escape(p4)
jump(p1, p2, p3, p4, i1)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_getarrayitem_pure_does_not_invalidate(self):
ops = """
@@ -1823,7 +2081,7 @@
escape(p3)
jump(p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_duplicate_getarrayitem_after_setarrayitem_two_arrays(self):
ops = """
@@ -1844,7 +2102,36 @@
escape(p4)
jump(p1, p2, p3, p4, i1)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_setfield_virtual(self):
+ ops = """
+ [p1, i2, i3, p4]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, p4, descr=nextdescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ guard_true(i3) []
+ i4 = int_neg(i2)
+ jump(p1, i2, i4, p4)
+ """
+ preamble = """
+ [p1, i2, i3, p4]
+ guard_true(i3) [p1, p4]
+ i4 = int_neg(i2)
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, p4, descr=nextdescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ jump(p1, i2, i4, p4)
+ """
+ expected = """
+ [p1, i2, i4, p4]
+ guard_true(i4) [p1, p4]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, p4, descr=nextdescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ jump(p1, i2, 1, p4)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bug_1(self):
ops = """
@@ -1866,8 +2153,7 @@
p3 = escape()
jump(i0, p3)
"""
- self.optimize_loop(ops, 'Not, Virtual(node_vtable, nextdescr=Not)',
- expected)
+ self.optimize_loop(ops, expected)
def test_bug_2(self):
ops = """
@@ -1889,8 +2175,7 @@
p3 = escape()
jump(i0, p3)
"""
- self.optimize_loop(ops, 'Not, VArray(arraydescr2, Not)',
- expected)
+ self.optimize_loop(ops, expected)
def test_bug_3(self):
ops = """
@@ -1912,17 +2197,34 @@
setfield_gc(p1a, p3a, descr=otherdescr)
jump(p1a)
"""
- expected = """
- [p2, p3]
+ preamble = """
+ [p1]
+ guard_nonnull_class(p1, ConstClass(node_vtable2)) []
+ p2 = getfield_gc(p1, descr=nextdescr)
guard_class(p2, ConstClass(node_vtable)) []
+ p3 = getfield_gc(p1, descr=otherdescr)
guard_class(p3, ConstClass(node_vtable)) []
setfield_gc(p3, p2, descr=otherdescr)
p3a = new_with_vtable(ConstClass(node_vtable))
escape(p3a)
- p2a = new_with_vtable(ConstClass(node_vtable))
- jump(p2a, p3a)
- """
- self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected)
+ jump(p3a)
+ """
+ expected = """
+ [p3a]
+ # p1=p1a(next=p2a, other=p3a), p2()
+ # p2 = getfield_gc(p1, descr=nextdescr) # p2a
+ # p3 = getfield_gc(p1, descr=otherdescr)# p3a
+ # setfield_gc(p3, p2, descr=otherdescr) # p3a.other = p2a
+ # p1a = new_with_vtable(ConstClass(node_vtable2))
+ # p2a = new_with_vtable(ConstClass(node_vtable))
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p3a, p2, descr=otherdescr) # p3a.other = p2a
+ p3anew = new_with_vtable(ConstClass(node_vtable))
+ escape(p3anew)
+ jump(p3anew)
+ """
+ #self.optimize_loop(ops, expected) # XXX Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)
+ self.optimize_loop(ops, expected, preamble)
def test_bug_3bis(self):
ops = """
@@ -1944,17 +2246,31 @@
setfield_gc(p1a, p3a, descr=otherdescr)
jump(p1a)
"""
+ preamble = """
+ [p1]
+ guard_nonnull_class(p1, ConstClass(node_vtable2)) []
+ p2 = getfield_gc(p1, descr=nextdescr)
+ guard_class(p2, ConstClass(node_vtable)) []
+ p3 = getfield_gc(p1, descr=otherdescr)
+ guard_class(p3, ConstClass(node_vtable)) []
+ # p1a = new_with_vtable(ConstClass(node_vtable2))
+ p2a = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p3, p2a, descr=otherdescr)
+ p3a = new_with_vtable(ConstClass(node_vtable))
+ escape(p3a)
+ # setfield_gc(p1a, p2a, descr=nextdescr)
+ # setfield_gc(p1a, p3a, descr=otherdescr)
+ jump(p2a, p3a)
+ """
expected = """
[p2, p3]
- guard_class(p2, ConstClass(node_vtable)) []
- guard_class(p3, ConstClass(node_vtable)) []
p2a = new_with_vtable(ConstClass(node_vtable))
setfield_gc(p3, p2a, descr=otherdescr)
p3a = new_with_vtable(ConstClass(node_vtable))
escape(p3a)
jump(p2a, p3a)
"""
- self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected)
+ self.optimize_loop(ops, expected, preamble)
def test_bug_4(self):
ops = """
@@ -1963,7 +2279,18 @@
setfield_gc(ConstPtr(myptr), p9, descr=nextdescr)
jump(p30)
"""
- self.optimize_loop(ops, 'Not', ops)
+ preamble = """
+ [p9]
+ setfield_gc(ConstPtr(myptr), p9, descr=nextdescr)
+ jump()
+ """
+ expected = """
+ []
+ p30 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(ConstPtr(myptr), p30, descr=nextdescr)
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_invalid_loop_1(self):
ops = """
@@ -1974,10 +2301,9 @@
jump(p2)
"""
py.test.raises(InvalidLoop, self.optimize_loop,
- ops, 'Virtual(node_vtable)', None)
+ ops, ops)
def test_invalid_loop_2(self):
- py.test.skip("this would fail if we had Fixed again in the specnodes")
ops = """
[p1]
guard_class(p1, ConstClass(node_vtable2)) []
@@ -1987,7 +2313,7 @@
jump(p2)
"""
py.test.raises(InvalidLoop, self.optimize_loop,
- ops, '...', None)
+ ops, ops)
def test_invalid_loop_3(self):
ops = """
@@ -2000,9 +2326,8 @@
setfield_gc(p3, p4, descr=nextdescr)
jump(p3)
"""
- py.test.raises(InvalidLoop, self.optimize_loop, ops,
- 'Virtual(node_vtable, nextdescr=Virtual(node_vtable))',
- None)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+
def test_merge_guard_class_guard_value(self):
ops = """
@@ -2012,16 +2337,21 @@
guard_value(p1, ConstPtr(myptr)) [i1]
jump(p2, i0, i1, i3, p2)
"""
- expected = """
+ preamble = """
[p1, i0, i1, i2, p2]
guard_value(p1, ConstPtr(myptr)) [i0]
i3 = int_add(i1, i2)
- jump(p2, i0, i1, i3, p2)
- """
- self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
+ jump(p2, i0, i1, i3)
+ """
+ expected = """
+ [p2, i0, i1, i2]
+ guard_value(p2, ConstPtr(myptr)) [i0]
+ i3 = int_add(i1, i2)
+ jump(ConstPtr(myptr), i0, i1, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_merge_guard_nonnull_guard_class(self):
- self.make_fail_descr()
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1, descr=fdescr) [i0]
@@ -2029,17 +2359,22 @@
guard_class(p1, ConstClass(node_vtable)) [i1]
jump(p2, i0, i1, i3, p2)
"""
- expected = """
+ preamble = """
[p1, i0, i1, i2, p2]
guard_nonnull_class(p1, ConstClass(node_vtable), descr=fdescr) [i0]
i3 = int_add(i1, i2)
- jump(p2, i0, i1, i3, p2)
- """
- self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
- self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
+ jump(p2, i0, i1, i3)
+ """
+ expected = """
+ [p2, i0, i1, i2]
+ guard_nonnull_class(p2, ConstClass(node_vtable), descr=fdescr2) [i0]
+ i3 = int_add(i1, i2)
+ jump(p2, i0, i1, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+ #self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
def test_merge_guard_nonnull_guard_value(self):
- self.make_fail_descr()
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1, descr=fdescr) [i0]
@@ -2047,17 +2382,22 @@
guard_value(p1, ConstPtr(myptr)) [i1]
jump(p2, i0, i1, i3, p2)
"""
- expected = """
+ preamble = """
[p1, i0, i1, i2, p2]
guard_value(p1, ConstPtr(myptr), descr=fdescr) [i0]
i3 = int_add(i1, i2)
- jump(p2, i0, i1, i3, p2)
- """
- self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
- self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
+ jump(p2, i0, i1, i3)
+ """
+ expected = """
+ [p2, i0, i1, i2]
+ guard_value(p2, ConstPtr(myptr), descr=fdescr2) [i0]
+ i3 = int_add(i1, i2)
+ jump(ConstPtr(myptr), i0, i1, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+ #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
def test_merge_guard_nonnull_guard_class_guard_value(self):
- self.make_fail_descr()
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1, descr=fdescr) [i0]
@@ -2067,15 +2407,22 @@
guard_value(p1, ConstPtr(myptr)) [i1]
jump(p2, i0, i1, i4, p2)
"""
- expected = """
+ preamble = """
[p1, i0, i1, i2, p2]
guard_value(p1, ConstPtr(myptr), descr=fdescr) [i0]
i3 = int_add(i1, i2)
i4 = int_sub(i3, 1)
- jump(p2, i0, i1, i4, p2)
- """
- self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
- self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
+ jump(p2, i0, i1, i4)
+ """
+ expected = """
+ [p2, i0, i1, i2]
+ guard_value(p2, ConstPtr(myptr), descr=fdescr2) [i0]
+ i3 = int_add(i1, i2)
+ i4 = int_sub(i3, 1)
+ jump(ConstPtr(myptr), i0, i1, i4)
+ """
+ self.optimize_loop(ops, expected, preamble)
+ #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
def test_guard_class_oois(self):
ops = """
@@ -2085,12 +2432,16 @@
guard_true(i) []
jump(p1)
"""
- expected = """
+ preamble = """
[p1]
guard_class(p1, ConstClass(node_vtable2)) []
jump(p1)
"""
- self.optimize_loop(ops, "Not", expected)
+ expected = """
+ [p1]
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_oois_of_itself(self):
ops = """
@@ -2103,12 +2454,16 @@
guard_false(i2) []
jump(p0)
"""
- expected = """
+ preamble = """
[p0]
p1 = getfield_gc(p0, descr=nextdescr)
jump(p0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_remove_duplicate_pure_op(self):
ops = """
@@ -2127,7 +2482,7 @@
guard_true(i2) []
jump(p1, p2)
"""
- expected = """
+ preamble = """
[p1, p2]
i1 = ptr_eq(p1, p2)
i3 = int_add(i1, 1)
@@ -2138,7 +2493,13 @@
guard_true(i1) []
jump(p1, p2)
"""
- self.optimize_loop(ops, "Not, Not", expected)
+ expected = """
+ [p1, p2]
+ escape(2)
+ escape(2)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_remove_duplicate_pure_op_with_descr(self):
ops = """
@@ -2151,14 +2512,18 @@
guard_true(i3) []
jump(p1)
"""
- expected = """
+ preamble = """
[p1]
i0 = arraylen_gc(p1, descr=arraydescr)
i1 = int_gt(i0, 0)
guard_true(i1) []
jump(p1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [p1]
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_remove_duplicate_pure_op_ovf(self):
ops = """
@@ -2175,7 +2540,7 @@
escape(i4)
jump(i1)
"""
- expected = """
+ preamble = """
[i1]
i3 = int_add_ovf(i1, 1)
guard_no_overflow() []
@@ -2183,9 +2548,15 @@
guard_true(i3b) []
escape(i3)
escape(i3)
- jump(i1)
- """
- self.optimize_loop(ops, "Not", expected)
+ jump(i1, i3)
+ """
+ expected = """
+ [i1, i3]
+ escape(i3)
+ escape(i3)
+ jump(i1, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_int_and_or_with_zero(self):
ops = """
@@ -2200,7 +2571,7 @@
[i0, i1]
jump(i1, i0)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_fold_partially_constant_ops(self):
ops = """
@@ -2212,7 +2583,7 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
ops = """
[i0]
@@ -2223,7 +2594,7 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
ops = """
[i0]
@@ -2234,7 +2605,7 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_fold_partially_constant_ops_ovf(self):
ops = """
@@ -2247,7 +2618,7 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
ops = """
[i0]
@@ -2259,7 +2630,7 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
ops = """
[i0]
@@ -2271,406 +2642,10 @@
[i0]
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
# ----------
- def make_fail_descr(self):
- class FailDescr(compile.ResumeGuardDescr):
- oparse = None
- def _oparser_uses_descr_of_guard(self, oparse, fail_args):
- # typically called twice, before and after optimization
- if self.oparse is None:
- fdescr.rd_frame_info_list = resume.FrameInfo(None,
- "code", 11)
- fdescr.rd_snapshot = resume.Snapshot(None, fail_args)
- self.oparse = oparse
- #
- fdescr = instantiate(FailDescr)
- self.namespace['fdescr'] = fdescr
-
- def teardown_method(self, meth):
- self.namespace.pop('fdescr', None)
-
- def _verify_fail_args(self, boxes, oparse, text):
- import re
- r = re.compile(r"\bwhere\s+(\w+)\s+is a\s+(\w+)")
- parts = list(r.finditer(text))
- ends = [match.start() for match in parts] + [len(text)]
- #
- virtuals = {}
- for match, end in zip(parts, ends[1:]):
- pvar = match.group(1)
- fieldstext = text[match.end():end]
- if match.group(2) == 'varray':
- arrayname, fieldstext = fieldstext.split(':', 1)
- tag = ('varray', self.namespace[arrayname.strip()])
- elif match.group(2) == 'vstruct':
- if ',' in fieldstext:
- structname, fieldstext = fieldstext.split(',', 1)
- else:
- structname, fieldstext = fieldstext, ''
- tag = ('vstruct', self.namespace[structname.strip()])
- else:
- tag = ('virtual', self.namespace[match.group(2)])
- virtuals[pvar] = (tag, None, fieldstext)
- #
- r2 = re.compile(r"([\w\d()]+)[.](\w+)\s*=\s*([\w\d()]+)")
- pendingfields = []
- for match in r2.finditer(text):
- pvar = match.group(1)
- pfieldname = match.group(2)
- pfieldvar = match.group(3)
- pendingfields.append((pvar, pfieldname, pfieldvar))
- #
- def _variables_equal(box, varname, strict):
- if varname not in virtuals:
- if strict:
- assert box == oparse.getvar(varname)
- else:
- assert box.value == oparse.getvar(varname).value
- else:
- tag, resolved, fieldstext = virtuals[varname]
- if tag[0] == 'virtual':
- assert self.get_class_of_box(box) == tag[1]
- elif tag[0] == 'varray':
- pass # xxx check arraydescr
- elif tag[0] == 'vstruct':
- pass # xxx check typedescr
- else:
- assert 0
- if resolved is not None:
- assert resolved.value == box.value
- else:
- virtuals[varname] = tag, box, fieldstext
- #
- basetext = text.splitlines()[0]
- varnames = [s.strip() for s in basetext.split(',')]
- if varnames == ['']:
- varnames = []
- assert len(boxes) == len(varnames)
- for box, varname in zip(boxes, varnames):
- _variables_equal(box, varname, strict=True)
- for pvar, pfieldname, pfieldvar in pendingfields:
- box = oparse.getvar(pvar)
- fielddescr = self.namespace[pfieldname.strip()]
- fieldbox = executor.execute(self.cpu, None,
- rop.GETFIELD_GC,
- fielddescr,
- box)
- _variables_equal(fieldbox, pfieldvar, strict=True)
- #
- for match in parts:
- pvar = match.group(1)
- tag, resolved, fieldstext = virtuals[pvar]
- assert resolved is not None
- index = 0
- for fieldtext in fieldstext.split(','):
- fieldtext = fieldtext.strip()
- if not fieldtext:
- continue
- if tag[0] in ('virtual', 'vstruct'):
- fieldname, fieldvalue = fieldtext.split('=')
- fielddescr = self.namespace[fieldname.strip()]
- fieldbox = executor.execute(self.cpu, None,
- rop.GETFIELD_GC,
- fielddescr,
- resolved)
- elif tag[0] == 'varray':
- fieldvalue = fieldtext
- fieldbox = executor.execute(self.cpu, None,
- rop.GETARRAYITEM_GC,
- tag[1],
- resolved, ConstInt(index))
- else:
- assert 0
- _variables_equal(fieldbox, fieldvalue.strip(), strict=False)
- index += 1
-
- def check_expanded_fail_descr(self, expectedtext, guard_opnum):
- from pypy.jit.metainterp.test.test_resume import ResumeDataFakeReader
- from pypy.jit.metainterp.test.test_resume import MyMetaInterp
- guard_op, = [op for op in self.loop.operations if op.is_guard()]
- fail_args = guard_op.getfailargs()
- fdescr = guard_op.getdescr()
- assert fdescr.guard_opnum == guard_opnum
- reader = ResumeDataFakeReader(fdescr, fail_args,
- MyMetaInterp(self.cpu))
- boxes = reader.consume_boxes()
- self._verify_fail_args(boxes, fdescr.oparse, expectedtext)
-
- def test_expand_fail_1(self):
- self.make_fail_descr()
- ops = """
- [i1, i3]
- # first rename i3 into i4
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i3, descr=valuedescr)
- i4 = getfield_gc(p1, descr=valuedescr)
- #
- i2 = int_add(10, 5)
- guard_true(i1, descr=fdescr) [i2, i4]
- jump(i1, i4)
- """
- expected = """
- [i1, i3]
- guard_true(i1, descr=fdescr) [i3]
- jump(1, i3)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
- self.check_expanded_fail_descr('15, i3', rop.GUARD_TRUE)
-
- def test_expand_fail_2(self):
- self.make_fail_descr()
- ops = """
- [i1, i2]
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i2, descr=valuedescr)
- setfield_gc(p1, p1, descr=nextdescr)
- guard_true(i1, descr=fdescr) [p1]
- jump(i1, i2)
- """
- expected = """
- [i1, i2]
- guard_true(i1, descr=fdescr) [i2]
- jump(1, i2)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
- self.check_expanded_fail_descr('''ptr
- where ptr is a node_vtable, valuedescr=i2
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_3(self):
- self.make_fail_descr()
- ops = """
- [i1, i2, i3, p3]
- p1 = new_with_vtable(ConstClass(node_vtable))
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, 1, descr=valuedescr)
- setfield_gc(p1, p2, descr=nextdescr)
- setfield_gc(p2, i2, descr=valuedescr)
- setfield_gc(p2, p3, descr=nextdescr)
- guard_true(i1, descr=fdescr) [i3, p1]
- jump(i2, i1, i3, p3)
- """
- expected = """
- [i1, i2, i3, p3]
- guard_true(i1, descr=fdescr) [i3, i2, p3]
- jump(i2, 1, i3, p3)
- """
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
- self.check_expanded_fail_descr('''i3, p1
- where p1 is a node_vtable, valuedescr=1, nextdescr=p2
- where p2 is a node_vtable, valuedescr=i2, nextdescr=p3
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_4(self):
- for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1',
- 'i2,p1,p2', 'i2,p2,p1']:
- self.make_fail_descr()
- ops = """
- [i1, i2, i3]
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i3, descr=valuedescr)
- i4 = getfield_gc(p1, descr=valuedescr) # copy of i3
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i2, descr=valuedescr)
- setfield_gc(p1, p2, descr=nextdescr)
- setfield_gc(p2, i2, descr=valuedescr)
- guard_true(i1, descr=fdescr) [i4, i3, %s]
- jump(i1, i2, i3)
- """
- expected = """
- [i1, i2, i3]
- guard_true(i1, descr=fdescr) [i3, i2]
- jump(1, i2, i3)
- """
- self.optimize_loop(ops % arg, 'Not, Not, Not', expected)
- self.check_expanded_fail_descr('''i3, i3, %s
- where p1 is a node_vtable, valuedescr=i2, nextdescr=p2
- where p2 is a node_vtable, valuedescr=i2''' % arg,
- rop.GUARD_TRUE)
-
- def test_expand_fail_5(self):
- self.make_fail_descr()
- ops = """
- [i1, i2, i3, i4]
- p1 = new_with_vtable(ConstClass(node_vtable))
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i4, descr=valuedescr)
- setfield_gc(p1, p2, descr=nextdescr)
- setfield_gc(p2, i2, descr=valuedescr)
- setfield_gc(p2, p1, descr=nextdescr) # a cycle
- guard_true(i1, descr=fdescr) [i3, i4, p1, p2]
- jump(i2, i1, i3, i4)
- """
- expected = """
- [i1, i2, i3, i4]
- guard_true(i1, descr=fdescr) [i3, i4, i2]
- jump(i2, 1, i3, i4)
- """
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
- self.check_expanded_fail_descr('''i3, i4, p1, p2
- where p1 is a node_vtable, valuedescr=i4, nextdescr=p2
- where p2 is a node_vtable, valuedescr=i2, nextdescr=p1
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_6(self):
- self.make_fail_descr()
- ops = """
- [p0, i0, i1]
- guard_true(i0, descr=fdescr) [p0]
- p1 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p1, i1, descr=valuedescr)
- jump(p1, i1, i1)
- """
- expected = """
- [i1b, i0, i1]
- guard_true(i0, descr=fdescr) [i1b]
- jump(i1, i1, i1)
- """
- self.optimize_loop(ops, '''Virtual(node_vtable, valuedescr=Not),
- Not, Not''', expected)
- self.check_expanded_fail_descr('''p0
- where p0 is a node_vtable, valuedescr=i1b
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_varray(self):
- self.make_fail_descr()
- ops = """
- [i1]
- p1 = new_array(3, descr=arraydescr)
- setarrayitem_gc(p1, 1, i1, descr=arraydescr)
- setarrayitem_gc(p1, 0, 25, descr=arraydescr)
- guard_true(i1, descr=fdescr) [p1]
- i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
- jump(i2)
- """
- expected = """
- [i1]
- guard_true(i1, descr=fdescr) [i1]
- jump(1)
- """
- self.optimize_loop(ops, 'Not', expected)
- self.check_expanded_fail_descr('''p1
- where p1 is a varray arraydescr: 25, i1
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_vstruct(self):
- self.make_fail_descr()
- ops = """
- [i1, p1]
- p2 = new(descr=ssize)
- setfield_gc(p2, i1, descr=adescr)
- setfield_gc(p2, p1, descr=bdescr)
- guard_true(i1, descr=fdescr) [p2]
- i3 = getfield_gc(p2, descr=adescr)
- p3 = getfield_gc(p2, descr=bdescr)
- jump(i3, p3)
- """
- expected = """
- [i1, p1]
- guard_true(i1, descr=fdescr) [i1, p1]
- jump(1, p1)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
- self.check_expanded_fail_descr('''p2
- where p2 is a vstruct ssize, adescr=i1, bdescr=p1
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_v_all_1(self):
- self.make_fail_descr()
- ops = """
- [i1, p1a, i2]
- p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2)
- p7v = getfield_gc(p6s, descr=bdescr)
- p5s = new(descr=ssize)
- setfield_gc(p5s, i2, descr=adescr)
- setfield_gc(p5s, p7v, descr=bdescr)
- setarrayitem_gc(p1a, 1, p5s, descr=arraydescr2)
- guard_true(i1, descr=fdescr) [p1a]
- p2s = new(descr=ssize)
- p3v = new_with_vtable(ConstClass(node_vtable))
- p4a = new_array(2, descr=arraydescr2)
- setfield_gc(p2s, i1, descr=adescr)
- setfield_gc(p2s, p3v, descr=bdescr)
- setfield_gc(p3v, i2, descr=valuedescr)
- setarrayitem_gc(p4a, 0, p2s, descr=arraydescr2)
- jump(i1, p4a, i2)
- """
- expected = """
- [i1, ia, iv, pnull, i2]
- guard_true(i1, descr=fdescr) [ia, iv, i2]
- jump(1, 1, i2, NULL, i2)
- """
- self.optimize_loop(ops, '''
- Not,
- VArray(arraydescr2,
- VStruct(ssize,
- adescr=Not,
- bdescr=Virtual(node_vtable,
- valuedescr=Not)),
- Not),
- Not''', expected)
- self.check_expanded_fail_descr('''p1a
- where p1a is a varray arraydescr2: p6s, p5s
- where p6s is a vstruct ssize, adescr=ia, bdescr=p7v
- where p5s is a vstruct ssize, adescr=i2, bdescr=p7v
- where p7v is a node_vtable, valuedescr=iv
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_lazy_setfield_1(self):
- self.make_fail_descr()
- ops = """
- [p1, i2, i3]
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p2, i2, descr=valuedescr)
- setfield_gc(p1, p2, descr=nextdescr)
- guard_true(i3, descr=fdescr) []
- i4 = int_neg(i2)
- setfield_gc(p1, NULL, descr=nextdescr)
- jump(p1, i2, i4)
- """
- expected = """
- [p1, i2, i3]
- guard_true(i3, descr=fdescr) [p1, i2]
- i4 = int_neg(i2)
- setfield_gc(p1, NULL, descr=nextdescr)
- jump(p1, i2, i4)
- """
- self.optimize_loop(ops, 'Not, Not, Not', expected)
- self.loop.inputargs[0].value = self.nodebox.value
- self.check_expanded_fail_descr('''
- p1.nextdescr = p2
- where p2 is a node_vtable, valuedescr=i2
- ''', rop.GUARD_TRUE)
-
- def test_expand_fail_lazy_setfield_2(self):
- self.make_fail_descr()
- ops = """
- [i2, i3]
- p2 = new_with_vtable(ConstClass(node_vtable))
- setfield_gc(p2, i2, descr=valuedescr)
- setfield_gc(ConstPtr(myptr), p2, descr=nextdescr)
- guard_true(i3, descr=fdescr) []
- i4 = int_neg(i2)
- setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
- jump(i2, i4)
- """
- expected = """
- [i2, i3]
- guard_true(i3, descr=fdescr) [i2]
- i4 = int_neg(i2)
- setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
- jump(i2, i4)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
- self.check_expanded_fail_descr('''
- ConstPtr(myptr).nextdescr = p2
- where p2 is a node_vtable, valuedescr=i2
- ''', rop.GUARD_TRUE)
-
-
class TestLLtype(OptimizeOptTest, LLtypeMixin):
def test_residual_call_does_not_invalidate_caches(self):
@@ -2691,7 +2666,7 @@
escape(i1)
jump(p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_residual_call_invalidate_some_caches(self):
ops = """
@@ -2719,7 +2694,7 @@
escape(i2)
jump(p1, p2)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_residual_call_invalidate_arrays(self):
ops = """
@@ -2746,7 +2721,7 @@
escape(p4)
jump(p1, p2, i1)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_residual_call_invalidate_some_arrays(self):
ops = """
@@ -2781,7 +2756,7 @@
escape(i4)
jump(p1, p2, i1)
"""
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_residual_call_invalidates_some_read_caches_1(self):
ops = """
@@ -2801,7 +2776,7 @@
setfield_gc(p2, i3, descr=adescr)
jump(p1, i1, p2, i2)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_residual_call_invalidates_some_read_caches_2(self):
ops = """
@@ -2821,7 +2796,7 @@
setfield_gc(p2, i3, descr=adescr)
jump(p1, i1, p2, i2)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_residual_call_invalidates_some_read_caches_3(self):
ops = """
@@ -2833,7 +2808,7 @@
setfield_gc(p2, i3, descr=adescr)
jump(p1, i1, p2, i2)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_call_assembler_invalidates_caches(self):
ops = '''
@@ -2843,7 +2818,7 @@
setfield_gc(p1, i3, descr=valuedescr)
jump(p1, i3)
'''
- self.optimize_loop(ops, 'Not, Not', ops)
+ self.optimize_loop(ops, ops)
def test_call_pure_invalidates_caches(self):
# CALL_PURE should still force the setfield_gc() to occur before it
@@ -2861,7 +2836,7 @@
setfield_gc(p1, i3, descr=valuedescr)
jump(p1, i3)
'''
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_call_pure_constant_folding(self):
# CALL_PURE is not marked as is_always_pure(), because it is wrong
@@ -2869,6 +2844,7 @@
# time. Check that it is either constant-folded (and replaced by
# the result of the call, recorded as the first arg), or turned into
# a regular CALL.
+ # XXX can this test be improved with unrolling?
ops = '''
[i0, i1, i2]
escape(i1)
@@ -2877,14 +2853,23 @@
i4 = call_pure(43, 123456, 4, i0, 6, descr=plaincalldescr)
jump(i0, i3, i4)
'''
- expected = '''
+ preamble = '''
[i0, i1, i2]
escape(i1)
escape(i2)
i4 = call(123456, 4, i0, 6, descr=plaincalldescr)
- jump(i0, 42, i4)
+ jump(i0, i4)
'''
- self.optimize_loop(ops, 'Not, Not, Not', expected)
+ expected = '''
+ [i0, i2]
+ escape(42)
+ escape(i2)
+ i4 = call(123456, 4, i0, 6, descr=plaincalldescr)
+ jump(i0, i4)
+ '''
+ self.optimize_loop(ops, expected, preamble)
+
+ # ----------
def test_vref_nonvirtual_nonescape(self):
ops = """
@@ -2898,7 +2883,7 @@
i0 = force_token()
jump(p1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected, expected)
def test_vref_nonvirtual_escape(self):
ops = """
@@ -2921,7 +2906,7 @@
"""
# XXX we should optimize a bit more the case of a nonvirtual.
# in theory it is enough to just do 'p2 = p1'.
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected, expected)
def test_vref_virtual_1(self):
ops = """
@@ -2961,10 +2946,9 @@
setfield_gc(p2, -3, descr=virtualtokendescr)
jump(p0, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected, expected)
def test_vref_virtual_2(self):
- self.make_fail_descr()
ops = """
[p0, i1]
#
@@ -2991,7 +2975,7 @@
setfield_gc(p0, p2, descr=nextdescr)
#
call_may_force(i1, descr=mayforcevirtdescr)
- guard_not_forced(descr=fdescr) [p2, i1]
+ guard_not_forced(descr=fdescr2) [p2, i1]
#
setfield_gc(p0, NULL, descr=nextdescr)
p1 = new_with_vtable(ConstClass(node_vtable))
@@ -3004,14 +2988,13 @@
"""
# the point of this test is that 'i1' should show up in the fail_args
# of 'guard_not_forced', because it was stored in the virtual 'p1b'.
- self.optimize_loop(ops, 'Not, Not', expected)
- self.check_expanded_fail_descr('''p2, p1
- where p1 is a node_vtable, nextdescr=p1b
- where p1b is a node_vtable, valuedescr=i1
- ''', rop.GUARD_NOT_FORCED)
+ self.optimize_loop(ops, expected)
+ #self.check_expanded_fail_descr('''p2, p1
+ # where p1 is a node_vtable, nextdescr=p1b
+ # where p1b is a node_vtable, valuedescr=i1
+ # ''', rop.GUARD_NOT_FORCED)
def test_vref_virtual_and_lazy_setfield(self):
- self.make_fail_descr()
ops = """
[p0, i1]
#
@@ -3028,7 +3011,7 @@
setfield_gc(p0, NULL, descr=refdescr)
jump(p0, i1)
"""
- expected = """
+ preamble = """
[p0, i1]
i3 = force_token()
call(i1, descr=nonwritedescr)
@@ -3036,21 +3019,28 @@
setfield_gc(p0, NULL, descr=refdescr)
jump(p0, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ call(i1, descr=nonwritedescr)
+ guard_no_exception(descr=fdescr2) [i3, i1, p0]
+ setfield_gc(p0, NULL, descr=refdescr)
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
# the fail_args contain [i3, i1, p0]:
# - i3 is from the virtual expansion of p2
# - i1 is from the virtual expansion of p1
# - p0 is from the extra pendingfields
- self.loop.inputargs[0].value = self.nodeobjvalue
- self.check_expanded_fail_descr('''p2, p1
- p0.refdescr = p2
- where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3, virtualrefindexdescr=2
- where p1 is a node_vtable, nextdescr=p1b
- where p1b is a node_vtable, valuedescr=i1
- ''', rop.GUARD_NO_EXCEPTION)
+ #self.loop.inputargs[0].value = self.nodeobjvalue
+ #self.check_expanded_fail_descr('''p2, p1
+ # p0.refdescr = p2
+ # where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3, virtualrefindexdescr=2
+ # where p1 is a node_vtable, nextdescr=p1b
+ # where p1b is a node_vtable, valuedescr=i1
+ # ''', rop.GUARD_NO_EXCEPTION)
def test_vref_virtual_after_finish(self):
- self.make_fail_descr()
ops = """
[i1]
p1 = new_with_vtable(ConstClass(node_vtable))
@@ -3075,10 +3065,9 @@
guard_not_forced() []
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected, expected)
def test_vref_nonvirtual_and_lazy_setfield(self):
- self.make_fail_descr()
ops = """
[i1, p1]
p2 = virtual_ref(p1, 23)
@@ -3101,7 +3090,9 @@
guard_not_forced() [i1]
jump(i1, p1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected, expected)
+
+ # ----------
def test_arraycopy_1(self):
ops = '''
@@ -3115,10 +3106,10 @@
jump(i2)
'''
expected = '''
- [i0]
- jump(1)
+ []
+ jump()
'''
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_arraycopy_2(self):
ops = '''
@@ -3132,28 +3123,30 @@
jump(i2)
'''
expected = '''
- [i0]
- jump(3)
+ []
+ jump()
'''
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_arraycopy_not_virtual(self):
ops = '''
- [p0]
+ []
p1 = new_array(3, descr=arraydescr)
p2 = new_array(3, descr=arraydescr)
setarrayitem_gc(p1, 2, 10, descr=arraydescr)
setarrayitem_gc(p2, 2, 13, descr=arraydescr)
call(0, p1, p2, 0, 0, 3, descr=arraycopydescr)
- jump(p2)
+ escape(p2)
+ jump()
'''
expected = '''
- [p0]
+ []
p2 = new_array(3, descr=arraydescr)
setarrayitem_gc(p2, 2, 10, descr=arraydescr)
- jump(p2)
+ escape(p2)
+ jump()
'''
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_arraycopy_no_elem(self):
""" this was actually observed in the wild
@@ -3168,7 +3161,7 @@
[p1]
jump(p1)
'''
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_bound_lt(self):
ops = """
@@ -3179,13 +3172,18 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_noguard(self):
ops = """
@@ -3200,7 +3198,7 @@
i2 = int_lt(i0, 5)
jump(i2)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected, expected)
def test_bound_lt_noopt(self):
ops = """
@@ -3211,15 +3209,19 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_false(i1) []
i2 = int_lt(i0, 5)
guard_true(i2) []
- jump(4)
- """
- self.optimize_loop(ops, 'Not', expected)
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_rev(self):
ops = """
@@ -3230,13 +3232,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_false(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_tripple(self):
ops = """
@@ -3249,13 +3255,17 @@
guard_true(i3) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 0)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_add(self):
ops = """
@@ -3267,14 +3277,18 @@
guard_true(i3) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_true(i1) []
i2 = int_add(i0, 10)
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_add_before(self):
ops = """
@@ -3286,14 +3300,18 @@
guard_true(i1) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i2 = int_add(i0, 10)
i3 = int_lt(i2, 15)
guard_true(i3) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_add_ovf(self):
ops = """
@@ -3306,14 +3324,18 @@
guard_true(i3) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_true(i1) []
i2 = int_add(i0, 10)
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_add_ovf_before(self):
ops = """
@@ -3326,7 +3348,7 @@
guard_true(i1) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i2 = int_add_ovf(i0, 10)
guard_no_overflow() []
@@ -3334,7 +3356,12 @@
guard_true(i3) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ i2 = int_add(i0, 10)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_sub(self):
ops = """
@@ -3346,14 +3373,18 @@
guard_true(i3) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_true(i1) []
i2 = int_sub(i0, 10)
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lt_sub_before(self):
ops = """
@@ -3365,14 +3396,18 @@
guard_true(i1) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i2 = int_sub(i0, 10)
i3 = int_lt(i2, -5)
guard_true(i3) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_ltle(self):
ops = """
@@ -3383,13 +3418,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_lt(i0, 4)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lelt(self):
ops = """
@@ -3400,13 +3439,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_le(i0, 4)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_gt(self):
ops = """
@@ -3417,13 +3460,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_gt(i0, 5)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_gtge(self):
ops = """
@@ -3434,13 +3481,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_gt(i0, 5)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_gegt(self):
ops = """
@@ -3451,13 +3502,17 @@
guard_true(i2) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_ge(i0, 5)
guard_true(i1) []
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_ovf(self):
ops = """
@@ -3470,7 +3525,7 @@
guard_no_overflow() []
jump(i3)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_ge(i0, 0)
guard_true(i1) []
@@ -3479,7 +3534,14 @@
i3 = int_add(i0, 1)
jump(i3)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ i2 = int_lt(i0, 10)
+ guard_true(i2) []
+ i3 = int_add(i0, 1)
+ jump(i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_arraylen(self):
ops = """
@@ -3499,7 +3561,7 @@
setarrayitem_gc(p0, 0, p1)
jump(i0, p0)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_bound_strlen(self):
ops = """
@@ -3515,7 +3577,7 @@
i0 = strlen(p0)
jump(p0)
"""
- self.optimize_strunicode_loop(ops, 'Not', expected)
+ self.optimize_strunicode_loop(ops, expected, expected)
def test_addsub_const(self):
ops = """
@@ -3532,7 +3594,7 @@
i4 = int_mul(i0, i1)
jump(i4)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_addsub_int(self):
ops = """
@@ -3549,7 +3611,7 @@
i4 = int_add(i0, i1)
jump(i4, i10)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_addsub_int2(self):
ops = """
@@ -3566,7 +3628,7 @@
i4 = int_add(i0, i1)
jump(i4, i10)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ self.optimize_loop(ops, expected)
def test_framestackdepth_overhead(self):
ops = """
@@ -3587,17 +3649,144 @@
jump(p0, i22)
"""
expected = """
- [p0, i22]
- i1 = getfield_gc(p0, descr=valuedescr)
- i2 = int_gt(i1, i22)
- guard_false(i2) []
- i3 = int_add(i1, 1)
+ [p0, i22, i1]
i331 = force_token()
setfield_gc(p0, i1, descr=valuedescr)
- jump(p0, i22)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
-
+ jump(p0, i22, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_setgetfield_raw(self):
+ ops = """
+ [p4, p7, i30]
+ p16 = getfield_gc(p4, descr=valuedescr)
+ p17 = getarrayitem_gc(p4, 1, descr=arraydescr)
+ guard_value(p16, ConstPtr(myptr), descr=<Guard3>) []
+ i1 = getfield_raw(p7, descr=nextdescr)
+ i2 = int_add(i1, i30)
+ setfield_raw(p7, 7, descr=nextdescr)
+ setfield_raw(p7, i2, descr=nextdescr)
+ jump(p4, p7, i30)
+ """
+ expected = """
+ [p4, p7, i30]
+ i1 = getfield_raw(p7, descr=nextdescr)
+ i2 = int_add(i1, i30)
+ setfield_raw(p7, 7, descr=nextdescr)
+ setfield_raw(p7, i2, descr=nextdescr)
+ jump(p4, p7, i30)
+ """
+ self.optimize_loop(ops, expected, ops)
+
+ def test_setgetarrayitem_raw(self):
+ ops = """
+ [p4, p7, i30]
+ p16 = getfield_gc(p4, descr=valuedescr)
+ guard_value(p16, ConstPtr(myptr), descr=<Guard3>) []
+ p17 = getarrayitem_gc(p4, 1, descr=arraydescr)
+ i1 = getarrayitem_raw(p7, 1, descr=arraydescr)
+ i2 = int_add(i1, i30)
+ setarrayitem_raw(p7, 1, 7, descr=arraydescr)
+ setarrayitem_raw(p7, 1, i2, descr=arraydescr)
+ jump(p4, p7, i30)
+ """
+ expected = """
+ [p4, p7, i30]
+ i1 = getarrayitem_raw(p7, 1, descr=arraydescr)
+ i2 = int_add(i1, i30)
+ setarrayitem_raw(p7, 1, 7, descr=arraydescr)
+ setarrayitem_raw(p7, 1, i2, descr=arraydescr)
+ jump(p4, p7, i30)
+ """
+ self.optimize_loop(ops, expected, ops)
+
+ def test_pure(self):
+ ops = """
+ [p42]
+ p53 = getfield_gc(ConstPtr(myptr), descr=nextdescr)
+ p59 = getfield_gc_pure(p53, descr=valuedescr)
+ i61 = call(1, p59, descr=nonwritedescr)
+ jump(p42)
+ """
+ expected = """
+ [p42, p59]
+ i61 = call(1, p59, descr=nonwritedescr)
+ jump(p42, p59)
+
+ """
+ self.node.value = 5
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_guard_const(self):
+ ops = """
+ [p0]
+ p20 = getfield_gc(p0, descr=nextdescr)
+ guard_nonnull(p20) []
+ guard_class(p20, ConstClass(node_vtable)) []
+ guard_class(p20, ConstClass(node_vtable)) []
+ p23 = getfield_gc(p20, descr=valuedescr)
+ guard_isnull(p23) []
+ guard_class(p20, ConstClass(node_vtable)) []
+ guard_value(p20, ConstPtr(myptr)) []
+
+ p37 = getfield_gc(p0, descr=nextdescr)
+ guard_nonnull(p37) []
+ guard_class(p37, ConstClass(node_vtable)) []
+ guard_class(p37, ConstClass(node_vtable)) []
+ p40 = getfield_gc(p37, descr=valuedescr)
+ guard_isnull(p40) []
+ guard_class(p37, ConstClass(node_vtable)) []
+ guard_value(p37, ConstPtr(myptr)) []
+
+ p64 = call_may_force(p23, p40, descr=plaincalldescr)
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ p20 = getfield_gc(p0, descr=nextdescr)
+ guard_value(p20, ConstPtr(myptr)) []
+ p23 = getfield_gc(p20, descr=valuedescr)
+ guard_isnull(p23) []
+ p64 = call_may_force(NULL, NULL, descr=plaincalldescr)
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, expected)
+
+ def test_getfield_guard_const_preamble(self):
+ ops = """
+ [p0]
+ p01 = getfield_gc(p0, descr=nextdescr)
+ p02 = getfield_gc(p01, descr=valuedescr)
+ guard_value(p01, ConstPtr(myptr)) []
+ p11 = getfield_gc(p0, descr=nextdescr)
+ p12 = getfield_gc(p11, descr=valuedescr)
+ guard_value(p11, ConstPtr(myptr)) []
+ p64 = call_may_force(p02, p12, descr=plaincalldescr)
+
+ p21 = getfield_gc(p0, descr=nextdescr)
+ p22 = getfield_gc(p21, descr=valuedescr)
+ guard_value(p21, ConstPtr(myptr)) []
+ p31 = getfield_gc(p0, descr=nextdescr)
+ p32 = getfield_gc(p31, descr=valuedescr)
+ guard_value(p31, ConstPtr(myptr)) []
+ p65 = call_may_force(p22, p32, descr=plaincalldescr)
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ p01 = getfield_gc(p0, descr=nextdescr)
+ p02 = getfield_gc(p01, descr=valuedescr)
+ guard_value(p01, ConstPtr(myptr)) []
+ p64 = call_may_force(p02, p02, descr=plaincalldescr)
+
+ p21 = getfield_gc(p0, descr=nextdescr)
+ p22 = getfield_gc(p21, descr=valuedescr)
+ guard_value(p21, ConstPtr(myptr)) []
+ p65 = call_may_force(p22, p22, descr=plaincalldescr)
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected, expected)
+
def test_addsub_ovf(self):
ops = """
[i0]
@@ -3614,7 +3803,7 @@
i2 = int_sub(i1, 5)
jump(i2)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_subadd_ovf(self):
ops = """
@@ -3632,7 +3821,7 @@
i2 = int_add(i1, 5)
jump(i2)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_bound_and(self):
ops = """
@@ -3677,7 +3866,176 @@
guard_true(i15) []
jump(i1)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
+
+ def test_bound_xor(self):
+ ops = """
+ [i0, i1, i2]
+ it1 = int_ge(i1, 0)
+ guard_true(it1) []
+ it2 = int_gt(i2, 0)
+ guard_true(it2) []
+ ix1 = int_xor(i0, i0)
+ ix1t = int_ge(ix1, 0)
+ guard_true(ix1t) []
+ ix2 = int_xor(i0, i1)
+ ix2t = int_ge(ix2, 0)
+ guard_true(ix2t) []
+ ix3 = int_xor(i1, i0)
+ ix3t = int_ge(ix3, 0)
+ guard_true(ix3t) []
+ ix4 = int_xor(i1, i2)
+ ix4t = int_ge(ix4, 0)
+ guard_true(ix4t) []
+ jump(i0, i1, i2)
+ """
+ preamble = """
+ [i0, i1, i2]
+ it1 = int_ge(i1, 0)
+ guard_true(it1) []
+ it2 = int_gt(i2, 0)
+ guard_true(it2) []
+ ix2 = int_xor(i0, i1)
+ ix2t = int_ge(ix2, 0)
+ guard_true(ix2t) []
+ ix3 = int_xor(i1, i0)
+ ix3t = int_ge(ix3, 0)
+ guard_true(ix3t) []
+ ix4 = int_xor(i1, i2)
+ jump(i0, i1, i2)
+ """
+ expected = """
+ [i0, i1, i2]
+ jump(i0, i1, i2)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_bound_floordiv(self):
+ ops = """
+ [i0, i1, i2]
+ it1 = int_ge(i1, 0)
+ guard_true(it1) []
+ it2 = int_gt(i2, 0)
+ guard_true(it2) []
+ ix2 = int_floordiv(i0, i1)
+ ix2t = int_ge(ix2, 0)
+ guard_true(ix2t) []
+ ix3 = int_floordiv(i1, i0)
+ ix3t = int_ge(ix3, 0)
+ guard_true(ix3t) []
+ ix4 = int_floordiv(i1, i2)
+ ix4t = int_ge(ix4, 0)
+ guard_true(ix4t) []
+ jump(i0, i1, i2)
+ """
+ preamble = """
+ [i0, i1, i2]
+ it1 = int_ge(i1, 0)
+ guard_true(it1) []
+ it2 = int_gt(i2, 0)
+ guard_true(it2) []
+ ix2 = int_floordiv(i0, i1)
+ ix2t = int_ge(ix2, 0)
+ guard_true(ix2t) []
+ ix3 = int_floordiv(i1, i0)
+ ix3t = int_ge(ix3, 0)
+ guard_true(ix3t) []
+ ix4 = int_floordiv(i1, i2)
+ jump(i0, i1, i2)
+ """
+ expected = """
+ [i0, i1, i2]
+ jump(i0, i1, i2)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_bound_int_is_zero(self):
+ ops = """
+ [i1, i2a, i2b, i2c]
+ i3 = int_is_zero(i1)
+ i4 = int_gt(i2a, 7)
+ guard_true(i4) []
+ i5 = int_is_zero(i2a)
+ guard_false(i5) []
+ i6 = int_le(i2b, -7)
+ guard_true(i6) []
+ i7 = int_is_zero(i2b)
+ guard_false(i7) []
+ i8 = int_gt(i2c, -7)
+ guard_true(i8) []
+ i9 = int_is_zero(i2c)
+ jump(i1, i2a, i2b, i2c)
+ """
+ preamble = """
+ [i1, i2a, i2b, i2c]
+ i3 = int_is_zero(i1)
+ i4 = int_gt(i2a, 7)
+ guard_true(i4) []
+ i6 = int_le(i2b, -7)
+ guard_true(i6) []
+ i8 = int_gt(i2c, -7)
+ guard_true(i8) []
+ i9 = int_is_zero(i2c)
+ jump(i1, i2a, i2b, i2c)
+ """
+ expected = """
+ [i0, i1, i2, i3]
+ jump(i0, i1, i2, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_division(self):
+ ops = """
+ [i7, i6, i8]
+ it1 = int_gt(i7, 0)
+ guard_true(it1) []
+ it2 = int_gt(i6, 0)
+ guard_true(it2) []
+ i13 = int_is_zero(i6)
+ guard_false(i13) []
+ i15 = int_and(i8, i6)
+ i17 = int_eq(i15, -1)
+ guard_false(i17) []
+ i18 = int_floordiv(i7, i6)
+ i19 = int_xor(i7, i6)
+ i21 = int_lt(i19, 0)
+ i22 = int_mod(i7, i6)
+ i23 = int_is_true(i22)
+ i24 = int_and(i21, i23)
+ i25 = int_sub(i18, i24)
+ jump(i7, i25, i8)
+ """
+ preamble = """
+ [i7, i6, i8]
+ it1 = int_gt(i7, 0)
+ guard_true(it1) []
+ it2 = int_gt(i6, 0)
+ guard_true(it2) []
+ i15 = int_and(i8, i6)
+ i17 = int_eq(i15, -1)
+ guard_false(i17) []
+ i18 = int_floordiv(i7, i6)
+ i19 = int_xor(i7, i6)
+ i22 = int_mod(i7, i6)
+ i23 = int_is_true(i22)
+ jump(i7, i18, i8)
+ """
+ expected = """
+ [i7, i6, i8]
+ it2 = int_gt(i6, 0)
+ guard_true(it2) []
+ i15 = int_and(i8, i6)
+ i17 = int_eq(i15, -1)
+ guard_false(i17) []
+ i18 = int_floordiv(i7, i6)
+ i19 = int_xor(i7, i6)
+ i22 = int_mod(i7, i6)
+ i23 = int_is_true(i22)
+ jump(i7, i18, i8)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+
def test_subsub_ovf(self):
ops = """
@@ -3692,7 +4050,7 @@
guard_true(i4) []
jump(i0)
"""
- expected = """
+ preamble = """
[i0]
i1 = int_sub_ovf(1, i0)
guard_no_overflow() []
@@ -3701,45 +4059,56 @@
i3 = int_sub(1, i0)
jump(i0)
"""
- self.optimize_loop(ops, 'Not', expected)
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_eq(self):
ops = """
- [i0, i1]
+ []
+ i0 = escape()
+ i1 = escape()
i2 = int_le(i0, 4)
guard_true(i2) []
i3 = int_eq(i0, i1)
guard_true(i3) []
i4 = int_lt(i1, 5)
guard_true(i4) []
- jump(i0, i1)
- """
- expected = """
- [i0, i1]
+ jump()
+ """
+ expected = """
+ []
+ i0 = escape()
+ i1 = escape()
i2 = int_le(i0, 4)
guard_true(i2) []
i3 = int_eq(i0, i1)
guard_true(i3) []
- jump(i0, i1)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
+ jump()
+ """
+ self.optimize_loop(ops, expected)
def test_bound_eq_const(self):
ops = """
- [i0]
+ []
+ i0 = escape()
i1 = int_eq(i0, 7)
guard_true(i1) []
i2 = int_add(i0, 3)
- jump(i2)
- """
- expected = """
- [i0]
+ escape(i2)
+ jump()
+ """
+ expected = """
+ []
+ i0 = escape()
i1 = int_eq(i0, 7)
guard_true(i1) []
- jump(10)
-
- """
- self.optimize_loop(ops, 'Not', expected)
+ escape(10)
+ jump()
+ """
+ self.optimize_loop(ops, expected)
def test_bound_eq_const_not(self):
ops = """
@@ -3757,7 +4126,7 @@
jump(i2)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_bound_ne_const(self):
ops = """
@@ -3767,14 +4136,7 @@
i2 = int_add(i0, 3)
jump(i2)
"""
- expected = """
- [i0]
- i1 = int_ne(i0, 7)
- guard_false(i1) []
- jump(10)
-
- """
- self.optimize_loop(ops, 'Not', expected)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_bound_ne_const_not(self):
ops = """
@@ -3791,7 +4153,7 @@
i2 = int_add(i0, 3)
jump(i2)
"""
- self.optimize_loop(ops, 'Not', expected)
+ self.optimize_loop(ops, expected)
def test_bound_ltne(self):
ops = """
@@ -3802,13 +4164,17 @@
guard_true(i2) []
jump(i0, i1)
"""
- expected = """
+ preamble = """
[i0, i1]
i2 = int_lt(i0, 7)
guard_true(i2) []
jump(i0, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ expected = """
+ [i0, i1]
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_bound_lege_const(self):
ops = """
@@ -3820,17 +4186,150 @@
i3 = int_add(i0, 3)
jump(i3)
"""
- expected = """
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+
+ def test_bound_lshift(self):
+ ops = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_lshift(i1, i3)
+ i8 = int_le(i7, 14)
+ guard_true(i8) []
+ i8b = int_lshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_lshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i12 = int_lt(i0, 15)
+ guard_true(i12) []
+ i13 = int_lshift(i1b, i3)
+ i14 = int_le(i13, 14)
+ guard_true(i14) []
+ i15 = int_lshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ preamble = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_lshift(i1, i3)
+ i8 = int_le(i7, 14)
+ guard_true(i8) []
+ i8b = int_lshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_lshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i13 = int_lshift(i1b, i3)
+ i15 = int_lshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ expected = """
+ [i0, i1, i1b, i2, i3]
+ jump(i0, i1, i1b, i2, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_bound_rshift(self):
+ ops = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_rshift(i1, i3)
+ i8 = int_le(i7, 14)
+ guard_true(i8) []
+ i8b = int_rshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_rshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i12 = int_lt(i0, 25)
+ guard_true(i12) []
+ i13 = int_rshift(i1b, i3)
+ i14 = int_le(i13, 14)
+ guard_true(i14) []
+ i15 = int_rshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ preamble = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_rshift(i1, i3)
+ i8b = int_rshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_rshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i12 = int_lt(i0, 25)
+ guard_true(i12) []
+ i13 = int_rshift(i1b, i3)
+ i15 = int_rshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ expected = """
+ [i0, i1, i1b, i2, i3]
+ jump(i0, i1, i1b, i2, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_bound_dont_backpropagate_rshift(self):
+ ops = """
[i0]
- i1 = int_ge(i0, 7)
- guard_true(i1) []
- i2 = int_le(i0, 7)
- guard_true(i2) []
- jump(10)
-
- """
- self.optimize_loop(ops, 'Not', expected)
-
+ i3 = int_rshift(i0, 1)
+ i5 = int_eq(i3, 1)
+ guard_true(i5) []
+ i11 = int_add(i0, 1)
+ jump(i11)
+ """
+ self.optimize_loop(ops, ops, ops)
+
+
def test_mul_ovf(self):
ops = """
[i0, i1]
@@ -3849,7 +4348,7 @@
guard_true(i8) []
jump(i0, i1)
"""
- expected = """
+ preamble = """
[i0, i1]
i2 = int_and(i0, 255)
i3 = int_lt(i1, 5)
@@ -3861,7 +4360,11 @@
guard_true(i8) []
jump(i0, i1)
"""
- self.optimize_loop(ops, 'Not, Not', expected)
+ expected = """
+ [i0, i1]
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_mul_ovf_before(self):
ops = """
@@ -3878,7 +4381,7 @@
guard_false(i6) []
jump(i0, i1)
"""
- expected = """
+ preamble = """
[i0, i1]
i2 = int_and(i0, 255)
i22 = int_add(i2, 1)
@@ -3888,9 +4391,18 @@
guard_true(i4) []
i5 = int_gt(i3, 2)
guard_true(i5) []
- jump(i0, i1)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
+ 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)
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_sub_ovf_before(self):
ops = """
@@ -3908,7 +4420,7 @@
guard_false(i7) []
jump(i0, i1)
"""
- expected = """
+ preamble = """
[i0, i1]
i2 = int_and(i0, 255)
i3 = int_sub_ovf(i2, i1)
@@ -3917,18 +4429,101 @@
guard_true(i4) []
i5 = int_ge(i3, 2)
guard_true(i5) []
- jump(i0, i1)
- """
- self.optimize_loop(ops, 'Not, Not', expected)
-
+ 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)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_value_proven_to_be_constant_after_two_iterations(self):
+ class FakeDescr(AbstractDescr):
+ def __init__(self, name):
+ self.name = name
+ def sort_key(self):
+ return id(self)
+
+
+ for n in ('inst_w_seq', 'inst_index', 'inst_w_list', 'inst_length',
+ 'inst_start', 'inst_step'):
+ self.namespace[n] = FakeDescr(n)
+ ops = """
+ [p0, p1, p2, p3, i4, p5, i6, p7, p8, p9, p14]
+ guard_value(i4, 3) []
+ guard_class(p9, 17278984) []
+ guard_class(p9, 17278984) []
+ p22 = getfield_gc(p9, descr=inst_w_seq)
+ guard_nonnull(p22) []
+ i23 = getfield_gc(p9, descr=inst_index)
+ p24 = getfield_gc(p22, descr=inst_w_list)
+ guard_isnull(p24) []
+ i25 = getfield_gc(p22, descr=inst_length)
+ i26 = int_ge(i23, i25)
+ guard_true(i26) []
+ setfield_gc(p9, ConstPtr(myptr), descr=inst_w_seq)
+
+ guard_nonnull(p14) []
+ guard_class(p14, 17273920) []
+ guard_class(p14, 17273920) []
+
+ p75 = new_with_vtable(17278984)
+ setfield_gc(p75, p14, descr=inst_w_seq)
+ setfield_gc(p75, 0, descr=inst_index)
+ guard_class(p75, 17278984) []
+ guard_class(p75, 17278984) []
+ p79 = getfield_gc(p75, descr=inst_w_seq)
+ guard_nonnull(p79) []
+ i80 = getfield_gc(p75, descr=inst_index)
+ p81 = getfield_gc(p79, descr=inst_w_list)
+ guard_isnull(p81) []
+ i82 = getfield_gc(p79, descr=inst_length)
+ i83 = int_ge(i80, i82)
+ guard_false(i83) []
+ i84 = getfield_gc(p79, descr=inst_start)
+ i85 = getfield_gc(p79, descr=inst_step)
+ i86 = int_mul(i80, i85)
+ i87 = int_add(i84, i86)
+ i91 = int_add(i80, 1)
+ setfield_gc(p75, i91, descr=inst_index)
+
+ p110 = same_as(ConstPtr(myptr))
+ i112 = same_as(3)
+ i114 = same_as(39)
+ jump(p0, p1, p110, p3, i112, p5, i114, p7, p8, p75, p14)
+ """
+ expected = """
+ [p0, p1, p3, p5, p7, p8, p14, i82]
+ i115 = int_ge(1, i82)
+ guard_true(i115) []
+ jump(p0, p1, p3, p5, p7, p8, p14, 1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_inputargs_added_by_forcing_jumpargs(self):
+ # FXIME: Can this occur?
+ ops = """
+ [p0, p1, pinv]
+ i1 = getfield_gc(pinv, descr=valuedescr)
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, i1, descr=nextdescr)
+ """
+
# ----------
- def optimize_strunicode_loop(self, ops, spectext, optops):
+ def optimize_strunicode_loop(self, ops, optops, preamble=None):
+ if not preamble:
+ preamble = ops # FIXME: Force proper testing of preamble
# check with the arguments passed in
- self.optimize_loop(ops, spectext, optops)
+ self.optimize_loop(ops, optops, preamble)
# check with replacing 'str' with 'unicode' everywhere
- self.optimize_loop(ops.replace('str','unicode').replace('s"', 'u"'),
- spectext,
- optops.replace('str','unicode').replace('s"', 'u"'))
+ def r(s):
+ return s.replace('str','unicode').replace('s"', 'u"')
+ self.optimize_loop(r(ops), r(optops), r(preamble))
def test_newstr_1(self):
ops = """
@@ -3942,7 +4537,7 @@
[i0]
jump(i0)
"""
- self.optimize_strunicode_loop(ops, 'Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_newstr_2(self):
ops = """
@@ -3958,7 +4553,7 @@
[i0, i1]
jump(i1, i0)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_concat_1(self):
ops = """
@@ -3979,7 +4574,7 @@
copystrcontent(p2, p3, 0, i4, i5)
jump(p2, p3)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_concat_vstr2_str(self):
ops = """
@@ -4002,7 +4597,7 @@
copystrcontent(p2, p3, 0, 2, i4)
jump(i1, i0, p3)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_concat_str_vstr2(self):
ops = """
@@ -4026,7 +4621,7 @@
i6 = int_add(i5, 1) # will be killed by the backend
jump(i1, i0, p3)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_concat_str_str_str(self):
ops = """
@@ -4053,7 +4648,7 @@
copystrcontent(p3, p5, 0, i12b, i3b)
jump(p2, p3, p5)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_concat_str_cstr1(self):
ops = """
@@ -4072,7 +4667,7 @@
i5 = int_add(i4, 1) # will be killed by the backend
jump(p3)
"""
- self.optimize_strunicode_loop(ops, 'Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_concat_consts(self):
ops = """
@@ -4083,12 +4678,18 @@
escape(p3)
jump()
"""
+ preamble = """
+ []
+ p3 = call(0, s"ab", s"cde", descr=strconcatdescr)
+ escape(p3)
+ jump()
+ """
expected = """
[]
escape(s"abcde")
jump()
"""
- self.optimize_strunicode_loop(ops, '', expected)
+ self.optimize_strunicode_loop(ops, expected, preamble)
def test_str_slice_1(self):
ops = """
@@ -4103,7 +4704,7 @@
copystrcontent(p1, p2, i1, 0, i3)
jump(p2, i1, i2)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_slice_2(self):
ops = """
@@ -4117,7 +4718,7 @@
copystrcontent(p1, p2, 0, 0, i2)
jump(p2, i2)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_slice_3(self):
ops = """
@@ -4135,7 +4736,7 @@
copystrcontent(p1, p3, i6, 0, i5)
jump(p3, i1, i2, i3, i4)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_slice_getitem1(self):
ops = """
@@ -4153,7 +4754,7 @@
escape(i4)
jump(p1, i1, i2, i3)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_slice_plain(self):
ops = """
@@ -4171,7 +4772,7 @@
escape(i4)
jump(i3, i4)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
def test_str_slice_concat(self):
ops = """
@@ -4192,10 +4793,10 @@
copystrcontent(p2, p4, 0, i3, i4b)
jump(p4, i1, i2, p2)
"""
- self.optimize_strunicode_loop(ops, 'Not, Not, Not, Not', expected)
+ self.optimize_strunicode_loop(ops, expected)
# ----------
- def optimize_strunicode_loop_extradescrs(self, ops, spectext, optops):
+ def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None):
from pypy.jit.metainterp.optimizeopt import string
class FakeCallInfoCollection:
def callinfo_for_oopspec(self, oopspecindex):
@@ -4210,7 +4811,7 @@
oopspecindex)
#
self.callinfocollection = FakeCallInfoCollection()
- self.optimize_strunicode_loop(ops, spectext, optops)
+ self.optimize_strunicode_loop(ops, optops, preamble)
def test_str_equal_noop1(self):
ops = """
@@ -4219,7 +4820,7 @@
escape(i0)
jump(p1, p2)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not', ops)
+ self.optimize_strunicode_loop_extradescrs(ops, ops)
def test_str_equal_noop2(self):
ops = """
@@ -4244,7 +4845,7 @@
escape(i0)
jump(p1, p2, p3)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not',
+ self.optimize_strunicode_loop_extradescrs(ops,
expected)
def test_str_equal_slice1(self):
@@ -4262,7 +4863,7 @@
escape(i0)
jump(p1, i1, i2, p3)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+ self.optimize_strunicode_loop_extradescrs(ops,
expected)
def test_str_equal_slice2(self):
@@ -4280,7 +4881,7 @@
escape(i0)
jump(p1, i1, i2, p3)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+ self.optimize_strunicode_loop_extradescrs(ops,
expected)
def test_str_equal_slice3(self):
@@ -4294,14 +4895,13 @@
"""
expected = """
[p1, i1, i2, p3]
- guard_nonnull(p3) []
i4 = int_sub(i2, i1)
i0 = call(0, p1, i1, i4, p3, descr=streq_slice_nonnull_descr)
escape(i0)
jump(p1, i1, i2, p3)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
- expected)
+ self.optimize_strunicode_loop_extradescrs(ops,
+ expected, ops)
def test_str_equal_slice4(self):
ops = """
@@ -4318,7 +4918,7 @@
escape(i0)
jump(p1, i1, i2)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not',
+ self.optimize_strunicode_loop_extradescrs(ops,
expected)
def test_str_equal_slice5(self):
@@ -4338,7 +4938,7 @@
escape(i0)
jump(p1, i1, i2, i3)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+ self.optimize_strunicode_loop_extradescrs(ops,
expected)
def test_str_equal_none1(self):
@@ -4354,7 +4954,7 @@
escape(i0)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_none2(self):
ops = """
@@ -4369,7 +4969,7 @@
escape(i0)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_nonnull1(self):
ops = """
@@ -4381,12 +4981,11 @@
"""
expected = """
[p1]
- guard_nonnull(p1) []
i0 = call(0, p1, s"hello world", descr=streq_nonnull_descr)
escape(i0)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_nonnull2(self):
ops = """
@@ -4398,13 +4997,12 @@
"""
expected = """
[p1]
- guard_nonnull(p1) []
i1 = strlen(p1)
i0 = int_eq(i1, 0)
escape(i0)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_nonnull3(self):
ops = """
@@ -4416,12 +5014,11 @@
"""
expected = """
[p1]
- guard_nonnull(p1) []
i0 = call(0, p1, 120, descr=streq_nonnull_char_descr)
escape(i0)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_nonnull4(self):
ops = """
@@ -4446,7 +5043,7 @@
escape(i0)
jump(p1, p2)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_chars0(self):
ops = """
@@ -4461,7 +5058,7 @@
escape(1)
jump(i1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_chars1(self):
ops = """
@@ -4478,7 +5075,7 @@
escape(i0)
jump(i1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_chars2(self):
ops = """
@@ -4499,7 +5096,7 @@
escape(i0)
jump(i1, i2)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_chars3(self):
ops = """
@@ -4514,7 +5111,7 @@
escape(i0)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str_equal_lengthmismatch1(self):
ops = """
@@ -4530,7 +5127,7 @@
escape(0)
jump(i1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str2unicode_constant(self):
ops = """
@@ -4544,7 +5141,7 @@
escape(u"xy")
jump()
"""
- self.optimize_strunicode_loop_extradescrs(ops, '', expected)
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
def test_str2unicode_nonconstant(self):
ops = """
@@ -4553,12 +5150,13 @@
escape(p1)
jump(p1)
"""
- self.optimize_strunicode_loop_extradescrs(ops, 'Not', ops)
+ self.optimize_strunicode_loop_extradescrs(ops, ops)
# more generally, supporting non-constant but virtual cases is
# not obvious, because of the exception UnicodeDecodeError that
# can be raised by ll_str2unicode()
+
##class TestOOtype(OptimizeOptTest, OOtypeMixin):
## def test_instanceof(self):
@@ -4572,7 +5170,7 @@
## [i0]
## jump(1)
## """
-## self.optimize_loop(ops, 'Not', expected)
+## self.optimize_loop(ops, expected)
## def test_instanceof_guard_class(self):
## ops = """
@@ -4586,4 +5184,4 @@
## guard_class(p0, ConstClass(node_vtable)) []
## jump(1, p0)
## """
-## self.optimize_loop(ops, 'Not, Not', expected)
+## self.optimize_loop(ops, expected)
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -1,11 +1,12 @@
import py
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.jit.metainterp.optimizeopt.virtualize import VirtualValue, OptValue, VArrayValue
+from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
+from pypy.jit.metainterp.optimizeopt.virtualize import VirtualValue, VArrayValue
from pypy.jit.metainterp.optimizeopt.virtualize import VStructValue
from pypy.jit.metainterp.resume import *
from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt
from pypy.jit.metainterp.history import ConstPtr, ConstFloat
-from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin
+from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin
from pypy.jit.metainterp import executor
from pypy.jit.codewriter import heaptracker
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
@@ -14,12 +14,14 @@
from pypy.jit.metainterp.logger import Logger
from pypy.jit.metainterp.jitprof import EmptyProfiler
from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE
-from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE
+from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \
+ ABORT_BAD_LOOP
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 import heaptracker
+from pypy.jit.metainterp.optimizeutil import RetraceLoop
# ____________________________________________________________
@@ -1384,6 +1386,11 @@
# ____________________________________________________________
+class RetraceState(object):
+ def __init__(self, metainterp, live_arg_boxes):
+ self.merge_point = len(metainterp.current_merge_points) - 1
+ self.live_arg_boxes = live_arg_boxes
+
class MetaInterp(object):
in_recursion = 0
@@ -1397,6 +1404,7 @@
self.portal_trace_positions = []
self.free_frames_list = []
self.last_exc_value_box = None
+ self.retracing_loop_from = None
def perform_call(self, jitcode, boxes, greenkey=None):
# causes the metainterp to enter the given subfunction
@@ -1747,7 +1755,15 @@
# that failed;
# - if self.resumekey is a ResumeFromInterpDescr, it starts directly
# from the interpreter.
- self.compile_bridge(live_arg_boxes)
+ if not self.retracing_loop_from:
+ try:
+ self.compile_bridge(live_arg_boxes)
+ except RetraceLoop:
+ start = len(self.history.operations)
+ self.current_merge_points.append((live_arg_boxes, start))
+ self.retracing_loop_from = RetraceState(self, live_arg_boxes)
+ return
+
# raises in case it works -- which is the common case, hopefully,
# at least for bridges starting from a guard.
@@ -1768,9 +1784,18 @@
else:
# Found! Compile it as a loop.
# raises in case it works -- which is the common case
- self.compile(original_boxes, live_arg_boxes, start)
+ if self.retracing_loop_from and \
+ self.retracing_loop_from.merge_point == j:
+ bridge_arg_boxes = self.retracing_loop_from.live_arg_boxes
+ self.compile_bridge_and_loop(original_boxes, \
+ live_arg_boxes, start,
+ bridge_arg_boxes)
+ else:
+ self.compile(original_boxes, live_arg_boxes, start)
# creation of the loop was cancelled!
- self.staticdata.log('cancelled, going on...')
+ #self.staticdata.log('cancelled, tracing more...')
+ self.staticdata.log('cancelled, stopping tracing')
+ raise SwitchToBlackhole(ABORT_BAD_LOOP)
# Otherwise, no loop found so far, so continue tracing.
start = len(self.history.operations)
@@ -1779,8 +1804,7 @@
def designate_target_loop(self, gmp):
loop_token = gmp.target_loop_token
num_green_args = self.jitdriver_sd.num_green_args
- residual_args = self.get_residual_args(loop_token.specnodes,
- gmp.argboxes[num_green_args:])
+ residual_args = gmp.argboxes[num_green_args:]
history.set_future_values(self.cpu, residual_args)
return loop_token
@@ -1836,11 +1860,13 @@
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, start)
+ loop_token = compile.compile_new_loop(self, old_loop_tokens,
+ greenkey, start)
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)
self.history.operations.pop() # remove the JUMP
+ # FIXME: Why is self.history.inputargs not restored?
def compile_bridge(self, live_arg_boxes):
num_green_args = self.jitdriver_sd.num_green_args
@@ -1848,12 +1874,51 @@
old_loop_tokens = self.get_compiled_merge_points(greenkey)
if len(old_loop_tokens) == 0:
return
+ #if self.resumekey.guard_opnum == rop.GUARD_CLASS:
+ # return # Kepp tracing for another iteration
self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
- target_loop_token = compile.compile_new_bridge(self, old_loop_tokens,
- self.resumekey)
- if target_loop_token is not None: # raise if it *worked* correctly
- raise GenerateMergePoint(live_arg_boxes, target_loop_token)
+ try:
+ target_loop_token = compile.compile_new_bridge(self,
+ old_loop_tokens,
+ self.resumekey)
+ if target_loop_token is not None: # raise if it *worked* correctly
+ raise GenerateMergePoint(live_arg_boxes, target_loop_token)
+ finally:
+ self.history.operations.pop() # remove the JUMP
+
+ def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
+ bridge_arg_boxes):
+ num_green_args = self.jitdriver_sd.num_green_args
+ original_inputargs = self.history.inputargs
+ greenkey = original_boxes[:num_green_args]
+ old_loop_tokens = self.get_compiled_merge_points(greenkey)
+ original_operations = self.history.operations
+ 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)
self.history.operations.pop() # remove the JUMP
+ if loop_token is None:
+ return
+
+ if loop_token.short_preamble:
+ old_loop_tokens[0].short_preamble.extend(loop_token.short_preamble)
+
+ self.history.inputargs = original_inputargs
+ self.history.operations = self.history.operations[:start]
+ live_arg_boxes = bridge_arg_boxes
+
+ self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
+ try:
+ target_loop_token = compile.compile_new_bridge(self,
+ [loop_token],
+ self.resumekey)
+ except RetraceLoop:
+ assert False
+ assert target_loop_token is not None
+
+ self.history.operations = original_operations
+ raise GenerateMergePoint(live_arg_boxes, old_loop_tokens[0])
def compile_done_with_this_frame(self, exitbox):
self.gen_store_back_in_virtualizable()
@@ -1892,16 +1957,6 @@
if target_loop_token is not loop_tokens[0]:
compile.giveup()
- def get_residual_args(self, specnodes, args):
- if specnodes is None: # it is None only for tests
- return args
- assert len(specnodes) == len(args)
- expanded_args = []
- for i in range(len(specnodes)):
- specnode = specnodes[i]
- specnode.extract_runtime_data(self.cpu, args[i], expanded_args)
- return expanded_args
-
@specialize.arg(1)
def initialize_original_boxes(self, jitdriver_sd, *args):
original_boxes = []
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
@@ -12,7 +12,6 @@
from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt
from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const
from pypy.jit.metainterp import history
-from pypy.jit.metainterp.specnode import NotSpecNode, more_general_specnodes
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.jit.metainterp.optimizeutil import InvalidLoop
from pypy.jit.metainterp.resume import NUMBERING
@@ -38,23 +37,24 @@
extraloops = [loop]
metainterp_sd.stats.view(errmsg=errmsg, extraloops=extraloops)
-def create_empty_loop(metainterp):
+def create_empty_loop(metainterp, name_prefix=''):
name = metainterp.staticdata.stats.name_for_new_loop()
- return TreeLoop(name)
+ return TreeLoop(name_prefix + name)
def make_loop_token(nb_args, jitdriver_sd):
loop_token = LoopToken()
- loop_token.specnodes = [prebuiltNotSpecNode] * nb_args
loop_token.outermost_jitdriver_sd = jitdriver_sd
return loop_token
-def record_loop_or_bridge(loop):
+def record_loop_or_bridge(metainterp_sd, loop):
"""Do post-backend recordings and cleanups on 'loop'.
"""
# get the original loop token (corresponding to 'loop', or if that is
# a bridge, to the loop that this bridge belongs to)
looptoken = loop.token
assert looptoken is not None
+ if metainterp_sd.warmrunnerdesc is not None: # for tests
+ assert looptoken.generation > 0 # has been registered with memmgr
wref = weakref.ref(looptoken)
for op in loop.operations:
descr = op.getdescr()
@@ -71,14 +71,17 @@
if descr is not looptoken:
looptoken.record_jump_to(descr)
op.setdescr(None) # clear reference, mostly for tests
+ if not we_are_translated():
+ op._jumptarget_number = descr.number
# mostly for tests: make sure we don't keep a reference to the LoopToken
loop.token = None
if not we_are_translated():
- loop._number = looptoken.number
+ loop._looptoken_number = looptoken.number
# ____________________________________________________________
-def compile_new_loop(metainterp, old_loop_tokens, start):
+def compile_new_loop(metainterp, old_loop_tokens, greenkey, start,
+ full_preamble_needed=True):
"""Try to compile a new loop by closing the current history back
to the first operation.
"""
@@ -95,6 +98,11 @@
loop_token = make_loop_token(len(loop.inputargs), jitdriver_sd)
loop.token = loop_token
loop.operations[-1].setdescr(loop_token) # patch the target of the JUMP
+
+ loop.preamble = create_empty_loop(metainterp, 'Preamble ')
+ loop.preamble.inputargs = loop.inputargs
+ loop.preamble.token = make_loop_token(len(loop.inputargs), jitdriver_sd)
+
try:
old_loop_token = jitdriver_sd.warmstate.optimize_loop(
metainterp_sd, old_loop_tokens, loop)
@@ -103,23 +111,33 @@
if old_loop_token is not None:
metainterp.staticdata.log("reusing old loop")
return old_loop_token
- send_loop_to_backend(metainterp_sd, loop, "loop")
- insert_loop_token(old_loop_tokens, loop_token)
- record_loop_or_bridge(loop)
- return loop_token
+
+ if loop.preamble.operations is not None:
+ send_loop_to_backend(metainterp_sd, loop, "loop")
+ record_loop_or_bridge(metainterp_sd, loop)
+ token = loop.preamble.token
+ if full_preamble_needed or not loop.preamble.token.short_preamble:
+ send_loop_to_backend(metainterp_sd, loop.preamble, "entry bridge")
+ insert_loop_token(old_loop_tokens, loop.preamble.token)
+ jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
+ greenkey, loop.preamble.token)
+ record_loop_or_bridge(metainterp_sd, loop.preamble)
+ return token
+ else:
+ send_loop_to_backend(metainterp_sd, loop, "loop")
+ insert_loop_token(old_loop_tokens, loop_token)
+ jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
+ greenkey, loop.token)
+ record_loop_or_bridge(metainterp_sd, loop)
+ return loop_token
def insert_loop_token(old_loop_tokens, loop_token):
# Find where in old_loop_tokens we should insert this new loop_token.
# The following algo means "as late as possible, but before another
# loop token that would be more general and so completely mask off
# the new loop_token".
- for i in range(len(old_loop_tokens)):
- if more_general_specnodes(old_loop_tokens[i].specnodes,
- loop_token.specnodes):
- old_loop_tokens.insert(i, loop_token)
- break
- else:
- old_loop_tokens.append(loop_token)
+ # XXX do we still need a list?
+ old_loop_tokens.append(loop_token)
def send_loop_to_backend(metainterp_sd, loop, type):
globaldata = metainterp_sd.globaldata
@@ -128,6 +146,11 @@
globaldata.loopnumbering += 1
metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type)
+ short = loop.token.short_preamble
+ if short:
+ metainterp_sd.logger_ops.log_short_preamble(short[-1].inputargs,
+ short[-1].operations)
+
if not we_are_translated():
show_loop(metainterp_sd, loop)
loop.check_consistency()
@@ -209,13 +232,10 @@
raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value)
-prebuiltNotSpecNode = NotSpecNode()
-
class TerminatingLoopToken(LoopToken):
terminating = True
def __init__(self, nargs, finishdescr):
- self.specnodes = [prebuiltNotSpecNode]*nargs
self.finishdescr = finishdescr
def make_done_loop_tokens():
@@ -568,14 +588,40 @@
# know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
prepare_last_operation(new_loop, target_loop_token)
resumekey.compile_and_attach(metainterp, new_loop)
- record_loop_or_bridge(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):
# normal case
- op.setdescr(target_loop_token) # patch the jump target
+ #op.setdescr(target_loop_token) # patch the jump target
+ pass
else:
# The target_loop_token is a pseudo loop token,
# e.g. loop_tokens_done_with_this_frame_void[0]
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
@@ -1,32 +1,29 @@
from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats
from pypy.jit.metainterp.history import BoxInt, INT
-from pypy.jit.metainterp.specnode import NotSpecNode, ConstantSpecNode
from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop
from pypy.jit.metainterp.compile import ResumeGuardDescr
from pypy.jit.metainterp.compile import ResumeGuardCountersInt
from pypy.jit.metainterp.compile import compile_tmp_callback
-from pypy.jit.metainterp import optimize, jitprof, typesystem, compile
-from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin
+from pypy.jit.metainterp import nounroll_optimize, jitprof, typesystem, compile
+from pypy.jit.metainterp.test.test_optimizeutil import LLtypeMixin
from pypy.jit.tool.oparser import parse
def test_insert_loop_token():
+ # XXX this test is a bit useless now that there are no specnodes
lst = []
#
tok1 = LoopToken()
- tok1.specnodes = [NotSpecNode()]
insert_loop_token(lst, tok1)
assert lst == [tok1]
#
tok2 = LoopToken()
- tok2.specnodes = [ConstantSpecNode(ConstInt(8))]
insert_loop_token(lst, tok2)
- assert lst == [tok2, tok1]
+ assert lst == [tok1, tok2]
#
tok3 = LoopToken()
- tok3.specnodes = [ConstantSpecNode(ConstInt(-13))]
insert_loop_token(lst, tok3)
- assert lst == [tok2, tok3, tok1]
+ assert lst == [tok1, tok2, tok3]
class FakeCPU:
@@ -41,7 +38,10 @@
pass
class FakeState:
- optimize_loop = staticmethod(optimize.optimize_loop)
+ optimize_loop = staticmethod(nounroll_optimize.optimize_loop)
+
+ def attach_unoptimized_bridge_from_interp(*args):
+ pass
class FakeGlobalData:
loopnumbering = 0
@@ -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)
assert loop_tokens == [loop_token]
assert loop_token.number == 1
assert staticdata.globaldata.loopnumbering == 2
@@ -102,11 +102,11 @@
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)
assert loop_token_2 is loop_token
assert loop_tokens == [loop_token]
assert len(cpu.seen) == 0
- assert staticdata.globaldata.loopnumbering == 2
+ assert staticdata.globaldata.loopnumbering == 2
def test_resume_guard_counters():
diff --git a/pypy/jit/metainterp/test/test_loop_spec.py b/pypy/jit/metainterp/test/test_loop_spec.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_loop_spec.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import py
-from pypy.rlib.jit import OPTIMIZER_FULL
-from pypy.jit.metainterp.test import test_loop
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-
-class LoopSpecTest(test_loop.LoopTest):
- optimizer = OPTIMIZER_FULL
- automatic_promotion_result = {
- 'int_add' : 3, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1,
- 'guard_value' : 1
- }
-
- # ====> test_loop.py
-
-class TestLLtype(LoopSpecTest, LLJitMixin):
- pass
-
-class TestOOtype(LoopSpecTest, OOJitMixin):
- pass
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -55,7 +55,7 @@
return False
def setdict(self, space, w_dict):
- typename = space.type(self).getname(space, '?')
+ typename = space.type(self).getname(space)
raise operationerrfmt(space.w_TypeError,
"attribute '__dict__' of %s objects "
"is not writable", typename)
@@ -72,7 +72,7 @@
raise NotImplementedError("only for interp-level user subclasses "
"from typedef.py")
- def getname(self, space, default):
+ def getname(self, space, default='?'):
try:
return space.str_w(space.getattr(self, space.wrap('__name__')))
except OperationError, e:
@@ -117,7 +117,7 @@
classname = wrappable_class_name(RequiredClass)
msg = "'%s' object expected, got '%s' instead"
raise operationerrfmt(space.w_TypeError, msg,
- classname, self.getclass(space).getname(space, '?'))
+ classname, self.getclass(space).getname(space))
# used by _weakref implemenation
@@ -125,7 +125,7 @@
return None
def setweakref(self, space, weakreflifeline):
- typename = space.type(self).getname(space, '?')
+ typename = space.type(self).getname(space)
raise operationerrfmt(space.w_TypeError,
"cannot create weak reference to '%s' object", typename)
@@ -364,8 +364,6 @@
def setbuiltinmodule(self, importname):
"""NOT_RPYTHON. load a lazy pypy/module and put it into sys.modules"""
- import sys
-
fullname = "pypy.module.%s" % importname
Module = __import__(fullname,
@@ -733,7 +731,7 @@
msg = "'%s' object expected, got '%s' instead"
raise operationerrfmt(self.w_TypeError, msg,
wrappable_class_name(RequiredClass),
- w_obj.getclass(self).getname(self, '?'))
+ w_obj.getclass(self).getname(self))
return obj
interp_w._annspecialcase_ = 'specialize:arg(1)'
@@ -1054,7 +1052,7 @@
raise
msg = "%s must be an integer, not %s"
raise operationerrfmt(self.w_TypeError, msg,
- objdescr, self.type(w_obj).getname(self, '?'))
+ objdescr, self.type(w_obj).getname(self))
try:
index = self.int_w(w_index)
except OperationError, err:
@@ -1070,7 +1068,7 @@
raise operationerrfmt(
w_exception,
"cannot fit '%s' into an index-sized "
- "integer", self.type(w_obj).getname(self, '?'))
+ "integer", self.type(w_obj).getname(self))
else:
return index
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
@@ -84,7 +84,7 @@
descr = self.getdescr()
if descr is not None:
descr = descr.clone_if_mutable()
- op = ResOperation(self.getopnum(), args, self.result, descr)
+ op = ResOperation(self.getopnum(), args[:], self.result, descr)
if not we_are_translated():
op.name = self.name
op.pc = self.pc
@@ -198,6 +198,7 @@
class GuardResOp(ResOpWithDescr):
_fail_args = None
+ _jump_target = None
def getfailargs(self):
return self._fail_args
@@ -205,14 +206,22 @@
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/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -178,12 +178,12 @@
def _ll_2_int_floordiv_ovf_zer(x, y):
if y == 0:
raise ZeroDivisionError
- if ((x + sys.maxint) & y) == -1: # detect "x = -sys.maxint-1, y = -1".
+ if x == -sys.maxint - 1 and y == -1:
raise OverflowError
return llop.int_floordiv(lltype.Signed, x, y)
def _ll_2_int_floordiv_ovf(x, y):
- if ((x + sys.maxint) & y) == -1: # detect "x = -sys.maxint-1, y = -1".
+ if x == -sys.maxint - 1 and y == -1:
raise OverflowError
return llop.int_floordiv(lltype.Signed, x, y)
@@ -195,12 +195,12 @@
def _ll_2_int_mod_ovf_zer(x, y):
if y == 0:
raise ZeroDivisionError
- if ((x + sys.maxint) & y) == -1: # detect "x = -sys.maxint-1, y = -1".
+ if x == -sys.maxint - 1 and y == -1:
raise OverflowError
return llop.int_mod(lltype.Signed, x, y)
def _ll_2_int_mod_ovf(x, y):
- if ((x + sys.maxint) & y) == -1: # detect "x = -sys.maxint-1, y = -1".
+ if x == -sys.maxint - 1 and y == -1:
raise OverflowError
return llop.int_mod(lltype.Signed, x, y)
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -328,7 +328,7 @@
return 'DoneWithThisFrameVoid()'
class DoneWithThisFrameInt(JitException):
- def __init__(self, result):
+ def __init__(self, result):
assert lltype.typeOf(result) is lltype.Signed
self.result = result
def __str__(self):
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -307,8 +307,9 @@
storage = self.storage
# make sure that nobody attached resume data to this guard yet
assert not storage.rd_numb
- numb, liveboxes_from_env, v = self.memo.number(values,
- storage.rd_snapshot)
+ snapshot = storage.rd_snapshot
+ assert snapshot is not None # is that true?
+ numb, liveboxes_from_env, v = self.memo.number(values, snapshot)
self.liveboxes_from_env = liveboxes_from_env
self.liveboxes = {}
storage.rd_numb = numb
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -444,7 +444,7 @@
pre = "bound"
else:
pre = "unbound"
- return "%s method %s" % (pre, self.w_function.getname(self.space, '?'))
+ return "%s method %s" % (pre, self.w_function.getname(self.space))
def call_args(self, args):
space = self.space
@@ -493,13 +493,13 @@
def descr_method_repr(self):
space = self.space
- name = self.w_function.getname(self.space, '?')
+ name = self.w_function.getname(self.space)
# XXX do we handle all cases sanely here?
if space.is_w(self.w_class, space.w_None):
w_class = space.type(self.w_instance)
else:
w_class = self.w_class
- typename = w_class.getname(self.space, '?')
+ typename = w_class.getname(self.space)
if self.w_instance is None:
s = "<unbound method %s.%s>" % (typename, name)
return space.wrap(s)
@@ -591,7 +591,7 @@
def descr_classmethod__new__(space, w_subtype, w_function):
if not space.is_true(space.callable(w_function)):
- typename = space.type(w_function).getname(space, '?')
+ typename = space.type(w_function).getname(space)
raise operationerrfmt(space.w_TypeError,
"'%s' object is not callable", typename)
instance = space.allocate_instance(ClassMethod, w_subtype)
diff --git a/pypy/tool/win32-build.bat b/pypy/tool/win32-build.bat
deleted file mode 100644
--- a/pypy/tool/win32-build.bat
+++ /dev/null
@@ -1,38 +0,0 @@
-setlocal
-
-set ROOTDIR=%~dp0..\..
-cd %ROOTDIR%
-
-set ZIPEXE=zip
-set PYTHON=c:\python26\python.exe
-set TRANSLATE=pypy/translator/goal/translate.py
-set TRANSLATEOPTS=--batch
-set TARGET=pypy/translator/goal/targetpypystandalone
-set TARGETOPTS=
-
-copy /y ..\expat-2.0.1\win32\bin\release\libexpat.dll .
-
-call :make_pypy pypy-1.2-win32.zip pypy.exe -Ojit
-call :make_pypy pypy-1.2-win32-nojit.zip pypy-nojit.exe
-call :make_pypy pypy-1.2-win32-stackless.zip pypy-stackless.exe --stackless
-REM call :make_pypy pypy-1.2-win32-sandbox.zip pypy-sandbox.exe --sandbox
-
-goto :EOF
-
-REM =========================================
-:make_pypy
-REM make_pypy subroutine
-REM %1 is the zip filename
-REM %2 is pypy.exe filename
-REM %3 and others are the translation options
-
-set ZIPFILE=%1
-set PYPYEXE=%2
-set EXTRAOPTS=%3 %4 %5 %6 %7 %8 %9
-
-%PYTHON% %TRANSLATE% --output=%PYPYEXE% %TRANSLATEOPTS% %EXTRAOPTS% %TARGET% %TARGETOPTS%
-del %ZIPFILE%
-del /s pypy\lib\*.pyc lib-python\*.pyc
-%ZIPEXE% %ZIPFILE% %PYPYEXE% *.dll
-%ZIPEXE% -r %ZIPFILE% pypy\lib lib-python
-%ZIPEXE% -d %ZIPFILE% lib-python\2.5.2\plat-*
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
@@ -42,8 +42,14 @@
descr.store_final_boxes(op, newboxes)
newoperations.extend(transform(op))
loop.operations = newoperations
+ jumpop = newoperations[-1]
+ if jumpop.getopnum() == rop.JUMP:
+ jumpop.setdescr(loop.token)
return None
def optimize_bridge(metainterp_sd, old_loops, loop):
optimize_loop(metainterp_sd, [], loop)
+ jumpop = loop.operations[-1]
+ if jumpop.getopnum() == rop.JUMP:
+ jumpop.setdescr(old_loops[0])
return old_loops[0]
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -9,6 +9,9 @@
"""Rewrite operations into equivalent, cheaper operations.
This includes already executed operations and constants.
"""
+
+ def reconstruct_for_next_iteration(self, optimizer, valuemap):
+ return self
def propagate_forward(self, op):
args = self.optimizer.make_args_key(op)
@@ -22,6 +25,18 @@
break
else:
self.emit_operation(op)
+
+ def test_emittable(self, op):
+ opnum = op.getopnum()
+ for value, func in optimize_guards:
+ if opnum == value:
+ try:
+ func(self, op, dryrun=True)
+ return self.is_emittable(op)
+ except InvalidLoop:
+ return False
+ return self.is_emittable(op)
+
def try_boolinvers(self, op, targs):
oldop = self.optimizer.pure_operations.get(targs, None)
@@ -142,7 +157,7 @@
self.emit_operation(ResOperation(rop.CALL, args, op.result,
op.getdescr()))
- def optimize_guard(self, op, constbox, emit_operation=True):
+ def optimize_guard(self, op, constbox, emit_operation=True, dryrun=False):
value = self.getvalue(op.getarg(0))
if value.is_constant():
box = value.box
@@ -150,32 +165,36 @@
if not box.same_constant(constbox):
raise InvalidLoop
return
+ if dryrun: return
if emit_operation:
self.emit_operation(op)
value.make_constant(constbox)
+ self.optimizer.turned_constant(value)
- def optimize_GUARD_ISNULL(self, op):
+ def optimize_GUARD_ISNULL(self, op, dryrun=False):
value = self.getvalue(op.getarg(0))
if value.is_null():
return
elif value.is_nonnull():
raise InvalidLoop
+ if dryrun: return
self.emit_operation(op)
value.make_constant(self.optimizer.cpu.ts.CONST_NULL)
- def optimize_GUARD_NONNULL(self, op):
+ def optimize_GUARD_NONNULL(self, op, dryrun=False):
value = self.getvalue(op.getarg(0))
if value.is_nonnull():
return
elif value.is_null():
raise InvalidLoop
+ if dryrun: return
self.emit_operation(op)
value.make_nonnull(len(self.optimizer.newoperations) - 1)
- def optimize_GUARD_VALUE(self, op):
+ def optimize_GUARD_VALUE(self, op, dryrun=False):
value = self.getvalue(op.getarg(0))
emit_operation = True
- if value.last_guard_index != -1:
+ if not dryrun and value.last_guard_index != -1:
# there already has been a guard_nonnull or guard_class or
# guard_nonnull_class on this value, which is rather silly.
# replace the original guard with a guard_value
@@ -193,25 +212,24 @@
emit_operation = False
constbox = op.getarg(1)
assert isinstance(constbox, Const)
- self.optimize_guard(op, constbox, emit_operation)
+ self.optimize_guard(op, constbox, emit_operation, dryrun)
- def optimize_GUARD_TRUE(self, op):
- self.optimize_guard(op, CONST_1)
+ def optimize_GUARD_TRUE(self, op, dryrun=False):
+ self.optimize_guard(op, CONST_1, dryrun=dryrun)
- def optimize_GUARD_FALSE(self, op):
- self.optimize_guard(op, CONST_0)
+ def optimize_GUARD_FALSE(self, op, dryrun=False):
+ self.optimize_guard(op, CONST_0, dryrun=dryrun)
- def optimize_GUARD_CLASS(self, op):
+ def optimize_GUARD_CLASS(self, op, dryrun=False):
value = self.getvalue(op.getarg(0))
expectedclassbox = op.getarg(1)
assert isinstance(expectedclassbox, Const)
realclassbox = value.get_constant_class(self.optimizer.cpu)
if realclassbox is not None:
- # the following assert should always be true for now,
- # because invalid loops that would fail it are detected
- # earlier, in optimizefindnode.py.
- assert realclassbox.same_constant(expectedclassbox)
- return
+ if realclassbox.same_constant(expectedclassbox):
+ return
+ raise InvalidLoop
+ if dryrun: return
emit_operation = True
if value.last_guard_index != -1:
# there already has been a guard_nonnull or guard_class or
@@ -237,7 +255,12 @@
last_guard_index = value.last_guard_index
value.make_constant_class(expectedclassbox, last_guard_index)
- def optimize_GUARD_NO_EXCEPTION(self, op):
+ def optimize_GUARD_NONNULL_CLASS(self, op, dryrun=False):
+ self.optimize_GUARD_NONNULL(op, True)
+ self.optimize_GUARD_CLASS(op, dryrun)
+
+ def optimize_GUARD_NO_EXCEPTION(self, op, dryrun=False):
+ if dryrun: return
if not self.optimizer.exception_might_have_happened:
return
self.emit_operation(op)
@@ -357,4 +380,4 @@
return False
optimize_ops = _findall(OptRewrite, 'optimize_')
-
+optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/pypy/jit/metainterp/optimize_nopspec.py b/pypy/jit/metainterp/optimize_nopspec.py
deleted file mode 100644
--- a/pypy/jit/metainterp/optimize_nopspec.py
+++ /dev/null
@@ -1,45 +0,0 @@
-
-from pypy.rlib.debug import debug_start, debug_stop
-from pypy.jit.metainterp.optimizeopt import optimize_loop_1, optimize_bridge_1
-from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder
-from pypy.jit.metainterp.optimizefindnode import BridgeSpecializationFinder
-
-def optimize_loop(metainterp_sd, old_loop_tokens, loop):
- debug_start("jit-optimize")
- try:
- return _optimize_loop(metainterp_sd, old_loop_tokens, loop)
- finally:
- debug_stop("jit-optimize")
-
-def _optimize_loop(metainterp_sd, old_loop_tokens, loop):
- cpu = metainterp_sd.cpu
- metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations)
- # XXX the following lines are probably still needed, to discard invalid
- # loops. bit silly to run a full perfect specialization and throw the
- # result away.
- finder = PerfectSpecializationFinder(cpu)
- finder.find_nodes_loop(loop, False)
- if old_loop_tokens:
- return old_loop_tokens[0]
- optimize_loop_1(metainterp_sd, loop)
- return None
-
-def optimize_bridge(metainterp_sd, old_loop_tokens, bridge):
- debug_start("jit-optimize")
- try:
- return _optimize_bridge(metainterp_sd, old_loop_tokens, bridge)
- finally:
- debug_stop("jit-optimize")
-
-def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge):
- cpu = metainterp_sd.cpu
- metainterp_sd.logger_noopt.log_loop(bridge.inputargs, bridge.operations)
- # XXX same comment as above applies
- finder = BridgeSpecializationFinder(cpu)
- finder.find_nodes_bridge(bridge)
- if old_loop_tokens:
- old_loop_token = old_loop_tokens[0]
- bridge.operations[-1].setdescr(old_loop_token) # patch jump target
- optimize_bridge_1(metainterp_sd, bridge)
- return old_loop_token
- return None
diff --git a/pypy/module/array/benchmark/loop.py b/pypy/module/array/benchmark/loop.py
deleted file mode 100644
--- a/pypy/module/array/benchmark/loop.py
+++ /dev/null
@@ -1,7 +0,0 @@
-def h():
- s=0
- i=0
- while i<100000:
- s+=i
- i+=1
- return s
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
@@ -1,18 +1,15 @@
-from pypy.jit.metainterp.specnode import SpecNode, NotSpecNode, ConstantSpecNode
-from pypy.jit.metainterp.specnode import AbstractVirtualStructSpecNode
-from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
-from pypy.jit.metainterp.specnode import VirtualArraySpecNode
-from pypy.jit.metainterp.specnode import VirtualStructSpecNode
+from pypy.jit.metainterp.history import Const, ConstInt, BoxInt
from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeutil import _findall
+from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs
+from pypy.jit.metainterp.optimizeutil import descrlist_dict
from pypy.rlib.objectmodel import we_are_translated
-from pypy.jit.metainterp.optimizeopt.optimizer import *
+from pypy.jit.metainterp.optimizeopt import optimizer
-class AbstractVirtualValue(OptValue):
+class AbstractVirtualValue(optimizer.OptValue):
_attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo')
box = None
- level = LEVEL_NONNULL
+ level = optimizer.LEVEL_NONNULL
_cached_vinfo = None
def __init__(self, optimizer, keybox, source_op=None):
@@ -47,6 +44,9 @@
def _really_force(self):
raise NotImplementedError("abstract base")
+ def reconstruct_for_next_iteration(self, _optimizer):
+ return optimizer.OptValue(self.force_box())
+
def get_fielddescrlist_cache(cpu):
if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
result = descrlist_dict()
@@ -67,7 +67,7 @@
return self._fields.get(ofs, default)
def setfield(self, ofs, fieldvalue):
- assert isinstance(fieldvalue, OptValue)
+ assert isinstance(fieldvalue, optimizer.OptValue)
self._fields[ofs] = fieldvalue
def _really_force(self):
@@ -123,9 +123,32 @@
fieldvalue = self._fields[ofs]
fieldvalue.get_args_for_fail(modifier)
+ def enum_forced_boxes(self, boxes, already_seen):
+ key = self.get_key_box()
+ if key in already_seen:
+ return
+ already_seen[key] = None
+ if self.box is None:
+ lst = self._get_field_descr_list()
+ for ofs in lst:
+ self._fields[ofs].enum_forced_boxes(boxes, already_seen)
+ else:
+ boxes.append(self.box)
+
+ def reconstruct_for_next_iteration(self, optimizer):
+ self.optimizer = optimizer
+ return self
+
+ def reconstruct_childs(self, new, valuemap):
+ assert isinstance(new, AbstractVirtualStructValue)
+ if new.box is None:
+ lst = self._get_field_descr_list()
+ for ofs in lst:
+ new._fields[ofs] = \
+ self._fields[ofs].get_reconstructed(new.optimizer, valuemap)
class VirtualValue(AbstractVirtualStructValue):
- level = LEVEL_KNOWNCLASS
+ level = optimizer.LEVEL_KNOWNCLASS
def __init__(self, optimizer, known_class, keybox, source_op=None):
AbstractVirtualStructValue.__init__(self, optimizer, keybox, source_op)
@@ -138,6 +161,8 @@
def __repr__(self):
cls_name = self.known_class.value.adr.ptr._obj._TYPE._name
+ if self._fields is None:
+ return '<VirtualValue FORCED cls=%s>' % (cls_name,)
field_names = [field.name for field in self._fields]
return "<VirtualValue cls=%s fields=%s>" % (cls_name, field_names)
@@ -167,7 +192,7 @@
return res
def setitem(self, index, itemvalue):
- assert isinstance(itemvalue, OptValue)
+ assert isinstance(itemvalue, optimizer.OptValue)
self._items[index] = itemvalue
def _really_force(self):
@@ -202,79 +227,33 @@
def _make_virtual(self, modifier):
return modifier.make_varray(self.arraydescr)
+ def enum_forced_boxes(self, boxes, already_seen):
+ key = self.get_key_box()
+ if key in already_seen:
+ return
+ already_seen[key] = None
+ if self.box is None:
+ for itemvalue in self._items:
+ itemvalue.enum_forced_boxes(boxes, already_seen)
+ else:
+ boxes.append(self.box)
-class __extend__(SpecNode):
- def setup_virtual_node(self, optimizer, box, newinputargs):
- raise NotImplementedError
- def teardown_virtual_node(self, optimizer, value, newexitargs):
- raise NotImplementedError
+ def reconstruct_for_next_iteration(self, optimizer):
+ self.optimizer = optimizer
+ return self
-class __extend__(NotSpecNode):
- def setup_virtual_node(self, optimizer, box, newinputargs):
- newinputargs.append(box)
- def teardown_virtual_node(self, optimizer, value, newexitargs):
- newexitargs.append(value.force_box())
+ def reconstruct_childs(self, new, valuemap):
+ assert isinstance(new, VArrayValue)
+ if new.box is None:
+ for i in range(len(self._items)):
+ new._items[i] = self._items[i].get_reconstructed(new.optimizer,
+ valuemap)
-class __extend__(ConstantSpecNode):
- def setup_virtual_node(self, optimizer, box, newinputargs):
- optimizer.make_constant(box, self.constbox)
- def teardown_virtual_node(self, optimizer, value, newexitargs):
- pass
-
-class __extend__(AbstractVirtualStructSpecNode):
- def setup_virtual_node(self, optimizer, box, newinputargs):
- vvalue = self._setup_virtual_node_1(optimizer, box)
- for ofs, subspecnode in self.fields:
- subbox = optimizer.new_box(ofs)
- subspecnode.setup_virtual_node(optimizer, subbox, newinputargs)
- vvaluefield = optimizer.getvalue(subbox)
- vvalue.setfield(ofs, vvaluefield)
- def _setup_virtual_node_1(self, optimizer, box):
- raise NotImplementedError
- def teardown_virtual_node(self, optimizer, value, newexitargs):
- assert value.is_virtual()
- for ofs, subspecnode in self.fields:
- subvalue = value.getfield(ofs, optimizer.new_const(ofs))
- subspecnode.teardown_virtual_node(optimizer, subvalue, newexitargs)
-
-class __extend__(VirtualInstanceSpecNode):
- def _setup_virtual_node_1(self, optimizer, box):
- return optimizer.make_virtual(self.known_class, box)
-
-class __extend__(VirtualStructSpecNode):
- def _setup_virtual_node_1(self, optimizer, box):
- return optimizer.make_vstruct(self.typedescr, box)
-
-class __extend__(VirtualArraySpecNode):
- def setup_virtual_node(self, optimizer, box, newinputargs):
- vvalue = optimizer.make_varray(self.arraydescr, len(self.items), box)
- for index in range(len(self.items)):
- subbox = optimizer.new_box_item(self.arraydescr)
- subspecnode = self.items[index]
- subspecnode.setup_virtual_node(optimizer, subbox, newinputargs)
- vvalueitem = optimizer.getvalue(subbox)
- vvalue.setitem(index, vvalueitem)
- def teardown_virtual_node(self, optimizer, value, newexitargs):
- assert value.is_virtual()
- for index in range(len(self.items)):
- subvalue = value.getitem(index)
- subspecnode = self.items[index]
- subspecnode.teardown_virtual_node(optimizer, subvalue, newexitargs)
-
-class OptVirtualize(Optimization):
+class OptVirtualize(optimizer.Optimization):
"Virtualize objects until they escape."
- def setup(self, virtuals):
- if not virtuals:
- return
-
- inputargs = self.optimizer.loop.inputargs
- specnodes = self.optimizer.loop.token.specnodes
- assert len(inputargs) == len(specnodes)
- newinputargs = []
- for i in range(len(inputargs)):
- specnodes[i].setup_virtual_node(self, inputargs[i], newinputargs)
- self.optimizer.loop.inputargs = newinputargs
+ def reconstruct_for_next_iteration(self, optimizer, valuemap):
+ return self
def make_virtual(self, known_class, box, source_op=None):
vvalue = VirtualValue(self.optimizer, known_class, box, source_op)
@@ -291,19 +270,6 @@
self.make_equal_to(box, vvalue)
return vvalue
- def optimize_JUMP(self, op):
- orgop = self.optimizer.loop.operations[-1]
- exitargs = []
- target_loop_token = orgop.getdescr()
- assert isinstance(target_loop_token, LoopToken)
- specnodes = target_loop_token.specnodes
- assert op.numargs() == len(specnodes)
- for i in range(len(specnodes)):
- value = self.getvalue(op.getarg(i))
- specnodes[i].teardown_virtual_node(self, value, exitargs)
- op = op.copy_and_change(op.getopnum(), args=exitargs[:])
- self.emit_operation(op)
-
def optimize_VIRTUAL_REF(self, op):
indexbox = op.getarg(1)
#
@@ -350,10 +316,10 @@
def optimize_GETFIELD_GC(self, op):
value = self.getvalue(op.getarg(0))
if value.is_virtual():
- # optimizefindnode should ensure that fieldvalue is found
assert isinstance(value, AbstractVirtualValue)
fieldvalue = value.getfield(op.getdescr(), None)
- assert fieldvalue is not None
+ if fieldvalue is None:
+ fieldvalue = self.optimizer.new_const(op.getdescr())
self.make_equal_to(op.result, fieldvalue)
else:
value.ensure_nonnull()
diff --git a/pypy/conftest.py b/pypy/conftest.py
--- a/pypy/conftest.py
+++ b/pypy/conftest.py
@@ -1,6 +1,7 @@
-import py, sys, os
+import py, sys, os, textwrap, types
from pypy.interpreter.gateway import app2interp_temp
from pypy.interpreter.error import OperationError
+from pypy.interpreter.function import Method
from pypy.tool.pytest import appsupport
from pypy.tool.option import make_config, make_objspace
from pypy.config.config import ConflictConfigError
@@ -14,8 +15,8 @@
rsyncdirs = ['.', '../lib-python', '../lib_pypy', '../demo']
rsyncignore = ['_cache']
-# PyPy's command line extra options (these are added
-# to py.test's standard options)
+# PyPy's command line extra options (these are added
+# to py.test's standard options)
#
def _set_platform(opt, opt_str, value, parser):
@@ -54,8 +55,8 @@
_SPACECACHE={}
def gettestobjspace(name=None, **kwds):
- """ helper for instantiating and caching space's for testing.
- """
+ """ helper for instantiating and caching space's for testing.
+ """
try:
config = make_config(option, objspace=name, **kwds)
except ConflictConfigError, e:
@@ -195,30 +196,30 @@
except AttributeError:
pass
-#
-# Interfacing/Integrating with py.test's collection process
+#
+# Interfacing/Integrating with py.test's collection process
#
#
def ensure_pytest_builtin_helpers(helpers='skip raises'.split()):
""" hack (py.test.) raises and skip into builtins, needed
- for applevel tests to run directly on cpython but
+ for applevel tests to run directly on cpython but
apparently earlier on "raises" was already added
- to module's globals.
- """
+ to module's globals.
+ """
import __builtin__
- for helper in helpers:
+ for helper in helpers:
if not hasattr(__builtin__, helper):
setattr(__builtin__, helper, getattr(py.test, helper))
def pytest_pycollect_makemodule(path, parent):
return PyPyModule(path, parent)
-class PyPyModule(py.test.collect.Module):
- """ we take care of collecting classes both at app level
- and at interp-level (because we need to stick a space
- at the class) ourselves.
- """
+class PyPyModule(py.test.collect.Module):
+ """ we take care of collecting classes both at app level
+ and at interp-level (because we need to stick a space
+ at the class) ourselves.
+ """
def __init__(self, *args, **kwargs):
if hasattr(sys, 'pypy_objspaceclass'):
option.conf_iocapture = "sys" # pypy cannot do FD-based
@@ -252,16 +253,16 @@
# return True
return False
- def setup(self):
+ def setup(self):
# stick py.test raise in module globals -- carefully
- ensure_pytest_builtin_helpers()
- super(PyPyModule, self).setup()
- # if hasattr(mod, 'objspacename'):
+ ensure_pytest_builtin_helpers()
+ super(PyPyModule, self).setup()
+ # if hasattr(mod, 'objspacename'):
# mod.space = getttestobjspace(mod.objspacename)
- def makeitem(self, name, obj):
- if isclass(obj) and self.classnamefilter(name):
- if name.startswith('AppTest'):
+ def makeitem(self, name, obj):
+ if isclass(obj) and self.classnamefilter(name):
+ if name.startswith('AppTest'):
return AppClassCollector(name, parent=self)
elif name.startswith('ExpectTest'):
if option.rundirect:
@@ -274,18 +275,18 @@
# return AppExpectClassCollector(name, parent=self)
else:
return IntClassCollector(name, parent=self)
-
- elif hasattr(obj, 'func_code') and self.funcnamefilter(name):
- if name.startswith('app_test_'):
+
+ elif hasattr(obj, 'func_code') and self.funcnamefilter(name):
+ if name.startswith('app_test_'):
assert not obj.func_code.co_flags & 32, \
- "generator app level functions? you must be joking"
- return AppTestFunction(name, parent=self)
- elif obj.func_code.co_flags & 32: # generator function
- return self.Generator(name, parent=self)
- else:
- return IntTestFunction(name, parent=self)
+ "generator app level functions? you must be joking"
+ return AppTestFunction(name, parent=self)
+ elif obj.func_code.co_flags & 32: # generator function
+ return self.Generator(name, parent=self)
+ else:
+ return IntTestFunction(name, parent=self)
-def skip_on_missing_buildoption(**ropts):
+def skip_on_missing_buildoption(**ropts):
__tracebackhide__ = True
import sys
options = getattr(sys, 'pypy_translation_info', None)
@@ -293,12 +294,12 @@
py.test.skip("not running on translated pypy "
"(btw, i would need options: %s)" %
(ropts,))
- for opt in ropts:
- if not options.has_key(opt) or options[opt] != ropts[opt]:
+ for opt in ropts:
+ if not options.has_key(opt) or options[opt] != ropts[opt]:
break
else:
return
- py.test.skip("need translated pypy with: %s, got %s"
+ py.test.skip("need translated pypy with: %s, got %s"
%(ropts,options))
def getwithoutbinding(x, name):
@@ -361,8 +362,8 @@
tb = sys.exc_info()[2]
if e.match(space, space.w_KeyboardInterrupt):
raise OpErrKeyboardInterrupt, OpErrKeyboardInterrupt(), tb
- appexcinfo = appsupport.AppExceptionInfo(space, e)
- if appexcinfo.traceback:
+ appexcinfo = appsupport.AppExceptionInfo(space, e)
+ if appexcinfo.traceback:
raise AppError, AppError(appexcinfo), tb
raise
@@ -420,7 +421,7 @@
target = self.obj
if option.runappdirect:
return target()
- space = gettestobjspace()
+ space = gettestobjspace()
filename = self._getdynfilename(target)
func = app2interp_temp(target, filename=filename)
print "executing", func
@@ -430,47 +431,56 @@
code = getattr(func, 'im_func', func).func_code
return "[%s:%s]" % (code.co_filename, code.co_firstlineno)
-class AppTestMethod(AppTestFunction):
-
- def setup(self):
- super(AppTestMethod, self).setup()
- instance = self.parent.obj
- w_instance = self.parent.w_instance
- space = instance.space
- for name in dir(instance):
- if name.startswith('w_'):
+class AppTestMethod(AppTestFunction):
+ def setup(self):
+ super(AppTestMethod, self).setup()
+ instance = self.parent.obj
+ w_instance = self.parent.w_instance
+ space = instance.space
+ for name in dir(instance):
+ if name.startswith('w_'):
if option.runappdirect:
# if the value is a function living on the class,
# don't turn it into a bound method here
obj = getwithoutbinding(instance, name)
setattr(instance, name[2:], obj)
else:
- space.setattr(w_instance, space.wrap(name[2:]),
- getattr(instance, name))
+ obj = getattr(instance, name)
+ if isinstance(obj, types.MethodType):
+ source = py.std.inspect.getsource(obj).lstrip()
+ w_func = space.appexec([], textwrap.dedent("""
+ ():
+ %s
+ return %s
+ """) % (source, name))
+ w_obj = Method(space, w_func, w_instance, space.w_None)
+ else:
+ w_obj = obj
+ space.setattr(w_instance, space.wrap(name[2:]), w_obj)
def runtest_perform(self):
target = self.obj
if option.runappdirect:
return target()
- space = target.im_self.space
+ space = target.im_self.space
filename = self._getdynfilename(target)
- func = app2interp_temp(target.im_func, filename=filename)
- w_instance = self.parent.w_instance
- self.execute_appex(space, func, space, w_instance)
+ func = app2interp_temp(target.im_func, filename=filename)
+ w_instance = self.parent.w_instance
+ self.execute_appex(space, func, space, w_instance)
class PyPyClassCollector(py.test.collect.Class):
def setup(self):
- cls = self.obj
+ cls = self.obj
if not hasattr(cls, 'spaceconfig'):
- cls.space = LazyObjSpaceGetter()
+ cls.space = LazyObjSpaceGetter()
else:
assert hasattr(cls, 'space') # set by pytest_runtest_setup
- super(PyPyClassCollector, self).setup()
+ super(PyPyClassCollector, self).setup()
class IntInstanceCollector(py.test.collect.Instance):
- Function = IntTestFunction
-
-class IntClassCollector(PyPyClassCollector):
+ Function = IntTestFunction
+
+class IntClassCollector(PyPyClassCollector):
Instance = IntInstanceCollector
def _haskeyword(self, keyword):
@@ -480,21 +490,21 @@
def _keywords(self):
return super(IntClassCollector, self)._keywords() + ['interplevel']
-class AppClassInstance(py.test.collect.Instance):
- Function = AppTestMethod
+class AppClassInstance(py.test.collect.Instance):
+ Function = AppTestMethod
- def setup(self):
- super(AppClassInstance, self).setup()
- instance = self.obj
- space = instance.space
- w_class = self.parent.w_class
+ def setup(self):
+ super(AppClassInstance, self).setup()
+ instance = self.obj
+ space = instance.space
+ w_class = self.parent.w_class
if option.runappdirect:
self.w_instance = instance
else:
self.w_instance = space.call_function(w_class)
-class AppClassCollector(PyPyClassCollector):
- Instance = AppClassInstance
+class AppClassCollector(PyPyClassCollector):
+ Instance = AppClassInstance
def _haskeyword(self, keyword):
return keyword == 'applevel' or \
@@ -503,11 +513,11 @@
def _keywords(self):
return super(AppClassCollector, self)._keywords() + ['applevel']
- def setup(self):
- super(AppClassCollector, self).setup()
- cls = self.obj
- space = cls.space
- clsname = cls.__name__
+ def setup(self):
+ super(AppClassCollector, self).setup()
+ cls = self.obj
+ space = cls.space
+ clsname = cls.__name__
if option.runappdirect:
w_class = cls
else:
@@ -515,7 +525,7 @@
space.wrap(clsname),
space.newtuple([]),
space.newdict())
- self.w_class = w_class
+ self.w_class = w_class
class ExpectTestMethod(py.test.collect.Function):
def safe_name(target):
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -7,17 +7,24 @@
^testresult$
^site-packages$
^bin$
+^pypy/bin/pypy-c
^pypy/module/cpyext/src/.+\.o$
-^pypy/bin/pypy-c
-^pypy/translator/jvm/src/pypy/.+\.class$
+^pypy/module/cpyext/src/.+\.obj$
^pypy/module/cpyext/test/.+\.errors$
^pypy/module/cpyext/test/.+\.o$
+^pypy/module/cpyext/test/.+\.obj$
+^pypy/module/cpyext/test/.+\.manifest$
^pypy/doc/.+\.html$
^pypy/doc/basicblock\.asc$
^pypy/doc/.+\.svninfo$
+^pypy/translator/c/src/libffi_msvc/.+\.obj$
+^pypy/translator/c/src/libffi_msvc/.+\.dll$
+^pypy/translator/c/src/libffi_msvc/.+\.lib$
+^pypy/translator/c/src/libffi_msvc/.+\.exp$
^pypy/translator/jvm/\.project$
^pypy/translator/jvm/\.classpath$
^pypy/translator/jvm/eclipse-bin$
+^pypy/translator/jvm/src/pypy/.+\.class$
^pypy/translator/benchmark/docutils$
^pypy/translator/benchmark/templess$
^pypy/translator/benchmark/gadfly$
@@ -27,6 +34,7 @@
^pypy/translator/goal/pypy-translation-snapshot$
^pypy/translator/goal/pypy-c
^pypy/translator/goal/.+\.exe$
+^pypy/translator/goal/.+\.dll$
^pypy/translator/goal/target.+-c$
^pypy/_cache$
^site-packages/.+\.egg$
More information about the Pypy-commit
mailing list