aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pypy/jit/metainterp/test/test_optimizebasic.py')
-rw-r--r--pypy/jit/metainterp/test/test_optimizebasic.py4593
1 files changed, 4593 insertions, 0 deletions
diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/test/test_optimizebasic.py
new file mode 100644
index 0000000000..40170c8535
--- /dev/null
+++ b/pypy/jit/metainterp/test/test_optimizebasic.py
@@ -0,0 +1,4593 @@
+import py
+from pypy.rlib.objectmodel import instantiate
+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.optimizeutil import InvalidLoop
+from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt
+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
+
+class Fake(object):
+ failargs_limit = 1000
+ storedebug = None
+
+class FakeMetaInterpStaticData(object):
+
+ def __init__(self, cpu):
+ self.cpu = cpu
+ self.profiler = EmptyProfiler()
+ self.options = Fake()
+ self.globaldata = Fake()
+
+def test_store_final_boxes_in_guard():
+ from pypy.jit.metainterp.compile import ResumeGuardDescr
+ from pypy.jit.metainterp.resume import tag, TAGBOX
+ b0 = BoxInt()
+ b1 = BoxInt()
+ opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
+ None)
+ fdescr = ResumeGuardDescr()
+ op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
+ # setup rd data
+ fi0 = resume.FrameInfo(None, "code0", 11)
+ fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33)
+ snapshot0 = resume.Snapshot(None, [b0])
+ fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1])
+ #
+ opt.store_final_boxes_in_guard(op)
+ if op.getfailargs() == [b0, b1]:
+ assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)]
+ assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)]
+ else:
+ assert op.getfailargs() == [b1, b0]
+ assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)]
+ assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)]
+ assert fdescr.rd_virtuals is None
+ assert fdescr.rd_consts == []
+
+def test_sharing_field_lists_of_virtual():
+ class FakeOptimizer(object):
+ class cpu(object):
+ pass
+ opt = FakeOptimizer()
+ virt1 = virtualize.AbstractVirtualStructValue(opt, None)
+ lst1 = virt1._get_field_descr_list()
+ assert lst1 == []
+ lst2 = virt1._get_field_descr_list()
+ assert lst1 is lst2
+ virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None))
+ lst3 = virt1._get_field_descr_list()
+ assert lst3 == [LLtypeMixin.valuedescr]
+ lst4 = virt1._get_field_descr_list()
+ assert lst3 is lst4
+
+ virt2 = virtualize.AbstractVirtualStructValue(opt, None)
+ lst5 = virt2._get_field_descr_list()
+ assert lst5 is lst1
+ virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None))
+ lst6 = virt1._get_field_descr_list()
+ assert lst6 is lst3
+
+def test_reuse_vinfo():
+ class FakeVInfo(object):
+ def set_content(self, fieldnums):
+ self.fieldnums = fieldnums
+ def equals(self, fieldnums):
+ return self.fieldnums == fieldnums
+ class FakeVirtualValue(virtualize.AbstractVirtualValue):
+ def _make_virtual(self, *args):
+ return FakeVInfo()
+ v1 = FakeVirtualValue(None, None, None)
+ vinfo1 = v1.make_virtual_info(None, [1, 2, 4])
+ vinfo2 = v1.make_virtual_info(None, [1, 2, 4])
+ assert vinfo1 is vinfo2
+ vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+ assert vinfo3 is not vinfo2
+ vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+ assert vinfo3 is vinfo4
+
+def test_descrlist_dict():
+ from pypy.jit.metainterp import optimizeutil
+ h1 = optimizeutil.descrlist_hash([])
+ h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr])
+ h3 = optimizeutil.descrlist_hash(
+ [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+ assert h1 != h2
+ assert h2 != h3
+ assert optimizeutil.descrlist_eq([], [])
+ assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr])
+ assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr],
+ [LLtypeMixin.valuedescr])
+ assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr],
+ [LLtypeMixin.nextdescr])
+ assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr],
+ [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+ assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr],
+ [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+
+ # descrlist_eq should compare by identity of the descrs, not by the result
+ # of sort_key
+ class FakeDescr(object):
+ def sort_key(self):
+ return 1
+
+ assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()])
+
+
+# ____________________________________________________________
+
+def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={},
+ text_right=None):
+ # 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, '-')
+ text_right = text_right or 'expected'
+ print '%s| %s' % ('optimized'.center(width), text_right.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 '-'*totwidth
+ 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):
+ self.metainterp_sd = metainterp_sd
+ self.original_greenkey = original_greenkey
+ def store_final_boxes(self, op, boxes):
+ op.setfailargs(boxes)
+ def __eq__(self, other):
+ return type(self) is type(other) # xxx obscure
+
+def _sortboxes(boxes):
+ _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3}
+ return sorted(boxes, key=lambda box: _kind2count[box.type])
+
+class BaseTestBasic(BaseTest):
+
+ def invent_fail_descr(self, fail_args):
+ if fail_args is None:
+ return None
+ descr = Storage()
+ descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11)
+ descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args))
+ return descr
+
+ def assert_equal(self, optimized, expected):
+ 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, optops):
+ loop = self.parse(ops)
+ #
+ self.loop = loop
+ metainterp_sd = FakeMetaInterpStaticData(self.cpu)
+ if hasattr(self, 'vrefinfo'):
+ metainterp_sd.virtualref_info = self.vrefinfo
+ if hasattr(self, 'callinfocollection'):
+ metainterp_sd.callinfocollection = self.callinfocollection
+ #
+ # XXX list the exact optimizations that are needed for each test
+ from pypy.jit.metainterp.optimizeopt import (OptIntBounds,
+ OptRewrite,
+ OptVirtualize,
+ OptString,
+ OptHeap,
+ Optimizer)
+ from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
+
+ optimizations = [OptIntBounds(),
+ OptRewrite(),
+ OptVirtualize(),
+ OptString(),
+ OptHeap(),
+ OptFfiCall(),
+ ]
+ optimizer = Optimizer(metainterp_sd, loop, optimizations)
+ optimizer.propagate_all_forward()
+ #
+ expected = self.parse(optops)
+ print '\n'.join([str(o) for o in loop.operations])
+ self.assert_equal(loop, expected)
+
+
+class BaseTestOptimizeBasic(BaseTestBasic):
+
+ 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, expected)
+
+ def test_constant_propagate(self):
+ ops = """
+ []
+ i0 = int_add(2, 3)
+ i1 = int_is_true(i0)
+ guard_true(i1) []
+ i2 = int_is_zero(i1)
+ guard_false(i2) []
+ guard_value(i0, 5) []
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constant_propagate_ovf(self):
+ ops = """
+ []
+ i0 = int_add_ovf(2, 3)
+ guard_no_overflow() []
+ i1 = int_is_true(i0)
+ guard_true(i1) []
+ i2 = int_is_zero(i1)
+ guard_false(i2) []
+ guard_value(i0, 5) []
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constfold_all(self):
+ from pypy.jit.backend.llgraph.llimpl import TYPES # xxx fish
+ from pypy.jit.metainterp.executor import execute_nonspec
+ from pypy.jit.metainterp.history import BoxInt
+ import random
+ for opnum in range(rop.INT_ADD, rop.SAME_AS+1):
+ try:
+ op = opname[opnum]
+ except KeyError:
+ continue
+ if 'FLOAT' in op:
+ continue
+ argtypes, restype = TYPES[op.lower()]
+ args = []
+ for argtype in argtypes:
+ assert argtype in ('int', 'bool')
+ args.append(random.randrange(1, 20))
+ assert restype in ('int', 'bool')
+ ops = """
+ []
+ i1 = %s(%s)
+ escape(i1)
+ jump()
+ """ % (op.lower(), ', '.join(map(str, args)))
+ argboxes = [BoxInt(a) for a in args]
+ expected_value = execute_nonspec(self.cpu, None, opnum,
+ argboxes).getint()
+ expected = """
+ []
+ escape(%d)
+ jump()
+ """ % expected_value
+ self.optimize_loop(ops, expected)
+
+ # ----------
+
+ def test_remove_guard_class_1(self):
+ ops = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_guard_class_2(self):
+ ops = """
+ [i0]
+ p0 = new_with_vtable(ConstClass(node_vtable))
+ escape(p0)
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ p0 = new_with_vtable(ConstClass(node_vtable))
+ escape(p0)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_guard_class_constant(self):
+ ops = """
+ [i0]
+ p0 = same_as(ConstPtr(myptr))
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constant_boolrewrite_lt(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 0)
+ guard_true(i1) []
+ i2 = int_ge(i0, 0)
+ guard_false(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constant_boolrewrite_gt(self):
+ ops = """
+ [i0]
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ i2 = int_le(i0, 0)
+ guard_false(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constant_boolrewrite_reflex(self):
+ ops = """
+ [i0]
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ i2 = int_lt(0, i0)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constant_boolrewrite_reflex_invers(self):
+ ops = """
+ [i0]
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ i2 = int_ge(0, i0)
+ guard_false(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_consecutive_guard_value_constfold(self):
+ ops = """
+ []
+ i0 = escape()
+ guard_value(i0, 0) []
+ i1 = int_add(i0, 1)
+ guard_value(i1, 1) []
+ i2 = int_add(i1, 2)
+ escape(i2)
+ jump()
+ """
+ expected = """
+ []
+ i0 = escape()
+ guard_value(i0, 0) []
+ escape(3)
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_guard_value_if_constant(self):
+ ops = """
+ [p1]
+ guard_value(p1, ConstPtr(myptr)) []
+ jump(ConstPtr(myptr))
+ """
+ expected = """
+ []
+ jump()
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Constant(myptr)', expected)
+
+ def test_ooisnull_oononnull_1(self):
+ ops = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ guard_nonnull(p0) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_is_true_1(self):
+ ops = """
+ [i0]
+ i1 = int_is_true(i0)
+ guard_true(i1) []
+ i2 = int_is_true(i0)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_is_true(i0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_is_true_is_zero(self):
+ py.test.skip("XXX implement me")
+ ops = """
+ [i0]
+ i1 = int_is_true(i0)
+ guard_true(i1) []
+ i2 = int_is_zero(i0)
+ guard_false(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_is_true(i0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_ooisnull_oononnull_2(self):
+ ops = """
+ [p0]
+ guard_nonnull(p0) []
+ guard_nonnull(p0) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ guard_nonnull(p0) []
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_ooisnull_on_null_ptr_1(self):
+ ops = """
+ []
+ p0 = escape()
+ guard_isnull(p0) []
+ guard_isnull(p0) []
+ jump()
+ """
+ expected = """
+ []
+ p0 = escape()
+ guard_isnull(p0) []
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_ooisnull_oononnull_via_virtual(self):
+ ops = """
+ [p0]
+ pv = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(pv, p0, descr=valuedescr)
+ guard_nonnull(p0) []
+ p1 = getfield_gc(pv, descr=valuedescr)
+ guard_nonnull(p1) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ guard_nonnull(p0) []
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_oois_1(self):
+ ops = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ i0 = ptr_ne(p0, NULL)
+ guard_true(i0) []
+ i1 = ptr_eq(p0, NULL)
+ guard_false(i1) []
+ i2 = ptr_ne(NULL, p0)
+ guard_true(i0) []
+ i3 = ptr_eq(NULL, p0)
+ guard_false(i1) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_nonnull_1(self):
+ ops = """
+ [p0]
+ setfield_gc(p0, 5, descr=valuedescr) # forces p0 != NULL
+ i0 = ptr_ne(p0, NULL)
+ guard_true(i0) []
+ i1 = ptr_eq(p0, NULL)
+ guard_false(i1) []
+ i2 = ptr_ne(NULL, p0)
+ guard_true(i0) []
+ i3 = ptr_eq(NULL, p0)
+ guard_false(i1) []
+ guard_nonnull(p0) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ setfield_gc(p0, 5, descr=valuedescr)
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_const_guard_value(self):
+ ops = """
+ []
+ i = int_add(5, 3)
+ guard_value(i, 8) []
+ jump()
+ """
+ expected = """
+ []
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_constptr_guard_value(self):
+ ops = """
+ []
+ p1 = escape()
+ guard_value(p1, ConstPtr(myptr)) []
+ jump()
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_guard_value_to_guard_true(self):
+ ops = """
+ [i]
+ i1 = int_lt(i, 3)
+ guard_value(i1, 1) [i]
+ jump(i)
+ """
+ expected = """
+ [i]
+ i1 = int_lt(i, 3)
+ guard_true(i1) [i]
+ jump(i)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_guard_value_to_guard_false(self):
+ ops = """
+ [i]
+ i1 = int_is_true(i)
+ guard_value(i1, 0) [i]
+ jump(i)
+ """
+ expected = """
+ [i]
+ i1 = int_is_true(i)
+ guard_false(i1) [i]
+ jump(i)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_guard_value_on_nonbool(self):
+ ops = """
+ [i]
+ i1 = int_add(i, 3)
+ guard_value(i1, 0) [i]
+ jump(i)
+ """
+ expected = """
+ [i]
+ i1 = int_add(i, 3)
+ guard_value(i1, 0) [i]
+ jump(-3)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_is_true_of_bool(self):
+ ops = """
+ [i0, i1]
+ i2 = int_gt(i0, i1)
+ i3 = int_is_true(i2)
+ i4 = int_is_true(i3)
+ guard_value(i4, 0) [i0, i1]
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_gt(i0, i1)
+ guard_false(i2) [i0, i1]
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+
+
+
+ def test_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.optimize_loop(ops, ops)
+
+ def test_p123_nested(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)
+ p1sub = new_with_vtable(ConstClass(node_vtable2))
+ setfield_gc(p1sub, i1, descr=valuedescr)
+ setfield_gc(p1, p1sub, descr=nextdescr)
+ jump(i1, p1, p2)
+ """
+ # The same as test_p123_simple, but with a virtual containing another
+ # virtual.
+ self.optimize_loop(ops, ops)
+
+ def test_p123_anti_nested(self):
+ ops = """
+ [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)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ jump(i1, p1, p2)
+ """
+ # 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, ops)
+
+ # ----------
+
+ def test_fold_guard_no_exception(self):
+ ops = """
+ [i]
+ guard_no_exception() []
+ i1 = int_add(i, 3)
+ guard_no_exception() []
+ i2 = call(i1, descr=nonwritedescr)
+ guard_no_exception() [i1, i2]
+ guard_no_exception() []
+ i3 = call(i2, descr=nonwritedescr)
+ jump(i1) # the exception is considered lost when we loop back
+ """
+ expected = """
+ [i]
+ guard_no_exception() []
+ 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)
+
+ # ----------
+
+ def test_call_loopinvariant(self):
+ ops = """
+ [i1]
+ i2 = call_loopinvariant(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i2, 1) []
+ i3 = call_loopinvariant(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i3, 1) []
+ i4 = call_loopinvariant(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i4, 1) []
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ i2 = call(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i2, 1) []
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+
+ # ----------
+
+ def test_virtual_1(self):
+ ops = """
+ [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)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
+ expected)
+
+ 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)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, Virtual(node_vtable, floatdescr=Not)',
+ expected)
+
+ 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)
+ """
+ expected = """
+ [i, i2]
+ i1 = int_add(i2, i)
+ jump(i, i1)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
+ expected)
+
+ def test_virtual_oois(self):
+ ops = """
+ [p0, p1, p2]
+ 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)
+ """
+ expected = """
+ [p2]
+ # all constant-folded :-)
+ jump(p2)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, '''Virtual(node_vtable),
+ Virtual(node_vtable),
+ Not''',
+ expected)
+ #
+ # to be complete, we also check the no-opt case where most comparisons
+ # are not removed. The exact set of comparisons removed depends on
+ # the details of the algorithm...
+ expected2 = """
+ [p0, p1, p2]
+ guard_nonnull(p0) []
+ i7 = ptr_ne(p0, p1)
+ guard_true(i7) []
+ i9 = ptr_ne(p0, p2)
+ guard_true(i9) []
+ i11 = ptr_ne(p2, p1)
+ guard_true(i11) []
+ jump(p0, p1, p2)
+ """
+ self.optimize_loop(ops, expected2)
+
+ def test_virtual_default_field(self):
+ ops = """
+ [p0]
+ i0 = getfield_gc(p0, descr=valuedescr)
+ guard_value(i0, 0) []
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ # 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.
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Virtual(node_vtable, valuedescr=Not)',
+ expected)
+
+ def test_virtual_3(self):
+ ops = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ i0 = getfield_gc(p1, descr=valuedescr)
+ i1 = int_add(i0, 1)
+ jump(i1)
+ """
+ expected = """
+ [i]
+ i1 = int_add(i, 1)
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_virtual_4(self):
+ ops = """
+ [i0, p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ i1 = getfield_gc(p0, descr=valuedescr)
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i0, i1)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(i3, p1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i0, i1)
+ jump(i3, i2)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
+ expected)
+
+ def test_virtual_5(self):
+ ops = """
+ [i0, p0]
+ guard_class(p0, ConstClass(node_vtable)) []
+ i1 = getfield_gc(p0, descr=valuedescr)
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i0, i1)
+ p2 = new_with_vtable(ConstClass(node_vtable2))
+ setfield_gc(p2, i1, descr=valuedescr)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i2, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ jump(i3, p1)
+ """
+ expected = """
+ [i0, i1, i1bis]
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i0, i1)
+ jump(i3, i2, i1)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops,
+ '''Not, Virtual(node_vtable,
+ valuedescr=Not,
+ nextdescr=Virtual(node_vtable2,
+ valuedescr=Not))''',
+ expected)
+
+ def test_virtual_constant_isnull(self):
+ ops = """
+ [i0]
+ p0 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p0, NULL, descr=nextdescr)
+ p2 = getfield_gc(p0, descr=nextdescr)
+ i1 = ptr_eq(p2, NULL)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(1)
+ """
+ self.optimize_loop(ops, expected)
+
+
+ def test_virtual_constant_isnonnull(self):
+ ops = """
+ [i0]
+ p0 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p0, ConstPtr(myptr), descr=nextdescr)
+ p2 = getfield_gc(p0, descr=nextdescr)
+ i1 = ptr_eq(p2, NULL)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_nonvirtual_1(self):
+ ops = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ i0 = getfield_gc(p1, descr=valuedescr)
+ i1 = int_add(i0, 1)
+ escape(p1)
+ escape(p1)
+ jump(i1)
+ """
+ expected = """
+ [i]
+ i1 = int_add(i, 1)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ escape(p1)
+ escape(p1)
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_nonvirtual_2(self):
+ ops = """
+ [i, p0]
+ i0 = getfield_gc(p0, descr=valuedescr)
+ escape(p0)
+ i1 = int_add(i0, i)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i1, descr=valuedescr)
+ jump(i, p1)
+ """
+ expected = ops
+ self.optimize_loop(ops, expected)
+
+ def test_nonvirtual_later(self):
+ ops = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ i1 = getfield_gc(p1, descr=valuedescr)
+ escape(p1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ i3 = int_add(i1, i2)
+ jump(i3)
+ """
+ expected = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ escape(p1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ i3 = int_add(i, i2)
+ jump(i3)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_nonvirtual_dont_write_null_fields_on_force(self):
+ ops = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ i1 = getfield_gc(p1, descr=valuedescr)
+ setfield_gc(p1, 0, descr=valuedescr)
+ escape(p1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(i2)
+ """
+ expected = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ escape(p1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_gc_pure_1(self):
+ ops = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ i1 = getfield_gc_pure(p1, descr=valuedescr)
+ jump(i1)
+ """
+ expected = """
+ [i]
+ jump(i)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_gc_pure_2(self):
+ ops = """
+ [i]
+ i1 = getfield_gc_pure(ConstPtr(myptr), descr=valuedescr)
+ jump(i1)
+ """
+ expected = """
+ [i]
+ jump(5)
+ """
+ self.node.value = 5
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_gc_nonpure_2(self):
+ ops = """
+ [i]
+ i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
+ jump(i1)
+ """
+ expected = ops
+ self.optimize_loop(ops, expected)
+
+ def test_varray_1(self):
+ ops = """
+ [i1]
+ p1 = new_array(3, descr=arraydescr)
+ i3 = arraylen_gc(p1, descr=arraydescr)
+ guard_value(i3, 3) []
+ setarrayitem_gc(p1, 1, i1, descr=arraydescr)
+ setarrayitem_gc(p1, 0, 25, descr=arraydescr)
+ i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
+ jump(i2)
+ """
+ expected = """
+ [i1]
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_varray_alloc_and_set(self):
+ ops = """
+ [i1]
+ p1 = new_array(2, descr=arraydescr)
+ setarrayitem_gc(p1, 0, 25, descr=arraydescr)
+ i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
+ jump(i2)
+ """
+ expected = """
+ [i1]
+ jump(0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_varray_float(self):
+ ops = """
+ [f1]
+ p1 = new_array(3, descr=floatarraydescr)
+ i3 = arraylen_gc(p1, descr=floatarraydescr)
+ guard_value(i3, 3) []
+ setarrayitem_gc(p1, 1, f1, descr=floatarraydescr)
+ setarrayitem_gc(p1, 0, 3.5, descr=floatarraydescr)
+ f2 = getarrayitem_gc(p1, 1, descr=floatarraydescr)
+ jump(f2)
+ """
+ expected = """
+ [f1]
+ jump(f1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_array_non_optimized(self):
+ ops = """
+ [i1, p0]
+ setarrayitem_gc(p0, 0, i1, descr=arraydescr)
+ guard_nonnull(p0) []
+ p1 = new_array(i1, descr=arraydescr)
+ jump(i1, p1)
+ """
+ expected = """
+ [i1, p0]
+ setarrayitem_gc(p0, 0, i1, descr=arraydescr)
+ p1 = new_array(i1, descr=arraydescr)
+ jump(i1, p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_nonvirtual_array_dont_write_null_fields_on_force(self):
+ ops = """
+ [i1]
+ p1 = new_array(5, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i1, descr=arraydescr)
+ setarrayitem_gc(p1, 1, 0, descr=arraydescr)
+ escape(p1)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ p1 = new_array(5, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i1, descr=arraydescr)
+ escape(p1)
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_varray_2(self):
+ ops = """
+ [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) []
+ p2 = new_array(2, descr=arraydescr)
+ setarrayitem_gc(p2, 1, i0, descr=arraydescr)
+ setarrayitem_gc(p2, 0, 20, descr=arraydescr)
+ jump(i0, p2)
+ """
+ expected = """
+ [i0, i1, i2]
+ i3 = int_sub(i1, i2)
+ guard_value(i3, 15) []
+ jump(i0, 20, i0)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected)
+
+ def test_p123_array(self):
+ ops = """
+ [i1, p2, p3]
+ i3 = getarrayitem_gc(p3, 0, descr=arraydescr)
+ escape(i3)
+ p1 = new_array(1, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i1, descr=arraydescr)
+ jump(i1, p1, p2)
+ """
+ # We cannot track virtuals that survive for more than two iterations.
+ self.optimize_loop(ops, ops)
+
+ def test_varray_forced_1(self):
+ ops = """
+ []
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, 3, descr=valuedescr)
+ i1 = getfield_gc(p2, descr=valuedescr) # i1 = const 3
+ p1 = new_array(i1, descr=arraydescr)
+ escape(p1)
+ i2 = arraylen_gc(p1)
+ escape(i2)
+ jump()
+ """
+ expected = """
+ []
+ p1 = new_array(3, descr=arraydescr)
+ escape(p1)
+ i2 = arraylen_gc(p1)
+ escape(i2)
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_vstruct_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)
+ """
+ expected = """
+ [i1, i2]
+ escape(i2)
+ jump(i1, i1)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, VStruct(ssize, adescr=Not)', expected)
+
+ def test_p123_vstruct(self):
+ ops = """
+ [i1, p2, p3]
+ i3 = getfield_gc(p3, descr=adescr)
+ escape(i3)
+ p1 = new(descr=ssize)
+ setfield_gc(p1, i1, descr=adescr)
+ jump(i1, p1, p2)
+ """
+ # We cannot track virtuals that survive for more than two iterations.
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_getfield_1(self):
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = getfield_gc(p2, descr=valuedescr)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ i4 = getfield_gc(p2, descr=valuedescr)
+ escape(i1)
+ escape(i2)
+ escape(i3)
+ escape(i4)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = getfield_gc(p2, descr=valuedescr)
+ escape(i1)
+ escape(i2)
+ escape(i1)
+ escape(i2)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getfield_after_setfield(self):
+ ops = """
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ escape(i2)
+ jump(p1, i1)
+ """
+ expected = """
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ escape(i1)
+ jump(p1, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_setfield_of_different_type_does_not_clear(self):
+ ops = """
+ [p1, p2, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, p1, descr=nextdescr)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ escape(i2)
+ jump(p1, p2, i1)
+ """
+ expected = """
+ [p1, p2, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, p1, descr=nextdescr)
+ escape(i1)
+ jump(p1, p2, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_setfield_of_same_type_clears(self):
+ ops = """
+ [p1, p2, i1, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=valuedescr)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ escape(i3)
+ jump(p1, p2, i1, i3)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_getfield_mergepoint_has_no_side_effects(self):
+ ops = """
+ [p1]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ debug_merge_point(15, 0)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ escape(i1)
+ escape(i2)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ debug_merge_point(15, 0)
+ escape(i1)
+ escape(i1)
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getfield_ovf_op_does_not_clear(self):
+ ops = """
+ [p1]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = int_add_ovf(i1, 14)
+ guard_no_overflow() []
+ i3 = getfield_gc(p1, descr=valuedescr)
+ escape(i2)
+ escape(i3)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = int_add_ovf(i1, 14)
+ guard_no_overflow() []
+ escape(i2)
+ escape(i1)
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getfield_setarrayitem_does_not_clear(self):
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ setarrayitem_gc(p2, 0, p1, descr=arraydescr2)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ escape(i1)
+ escape(i3)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ setarrayitem_gc(p2, 0, p1, descr=arraydescr2)
+ escape(i1)
+ escape(i1)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getfield_constant(self):
+ ops = """
+ []
+ i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
+ i2 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
+ escape(i1)
+ escape(i2)
+ jump()
+ """
+ expected = """
+ []
+ i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
+ escape(i1)
+ escape(i1)
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getfield_guard_value_const(self):
+ ops = """
+ [p1]
+ guard_value(p1, ConstPtr(myptr)) []
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
+ escape(i1)
+ escape(i2)
+ jump(p1)
+ """
+ expected = """
+ []
+ i1 = getfield_gc(ConstPtr(myptr), descr=valuedescr)
+ escape(i1)
+ escape(i1)
+ jump()
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Constant(myptr)', expected)
+
+ def test_duplicate_getfield_sideeffects_1(self):
+ ops = """
+ [p1]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ escape()
+ i2 = getfield_gc(p1, descr=valuedescr)
+ escape(i1)
+ escape(i2)
+ jump(p1)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_getfield_sideeffects_2(self):
+ ops = """
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ escape()
+ i2 = getfield_gc(p1, descr=valuedescr)
+ escape(i2)
+ jump(p1, i1)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_setfield_1(self):
+ ops = """
+ [p1, i1, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ expected = """
+ [p1, i1, i2]
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_setfield_2(self):
+ ops = """
+ [p1, i1, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ escape(i2)
+ jump(p1, i1, i3)
+ """
+ expected = """
+ [p1, i1, i3]
+ setfield_gc(p1, i3, descr=valuedescr)
+ escape(i1)
+ jump(p1, i1, i3)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_setfield_3(self):
+ ops = """
+ [p1, p2, i1, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i2 = getfield_gc(p2, descr=valuedescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ escape(i2)
+ jump(p1, p2, i1, i3)
+ """
+ # potential aliasing of p1 and p2 means that we cannot kill the
+ # the setfield_gc
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_setfield_4(self):
+ ops = """
+ [p1, i1, i2, p3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ #
+ # some operations on which the above setfield_gc cannot have effect
+ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+ i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+ i5 = int_add(i3, i4)
+ setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+ setfield_gc(p1, i4, descr=nextdescr)
+ #
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, p3)
+ """
+ expected = """
+ [p1, i1, i2, p3]
+ #
+ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+ 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)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_setfield_5(self):
+ ops = """
+ [p0, i1]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p0, p1, descr=nextdescr)
+ setfield_raw(i1, i1, descr=valuedescr) # random op with side-effects
+ p2 = getfield_gc(p0, descr=nextdescr)
+ i2 = getfield_gc(p2, descr=valuedescr)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ escape(i2)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ setfield_raw(i1, i1, descr=valuedescr)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ escape(i1)
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_setfield_sideeffects_1(self):
+ ops = """
+ [p1, i1, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ escape()
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_setfield_residual_guard_1(self):
+ ops = """
+ [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)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_setfield_residual_guard_2(self):
+ # the difference with the previous test is that the field value is
+ # a virtual, which we try hard to keep virtual
+ ops = """
+ [p1, i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, p2, descr=nextdescr)
+ guard_true(i3) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ expected = """
+ [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, expected)
+
+ def test_duplicate_setfield_residual_guard_3(self):
+ 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) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ expected = """
+ [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, expected)
+
+ def test_duplicate_setfield_residual_guard_4(self):
+ # test that the setfield_gc does not end up between int_eq and
+ # the following guard_true
+ ops = """
+ [p1, i1, i2, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i5 = int_eq(i3, 5)
+ guard_true(i5) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, i4)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_setfield_aliasing(self):
+ # a case where aliasing issues (and not enough cleverness) mean
+ # that we fail to remove any setfield_gc
+ ops = """
+ [p1, p2, i1, i2, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ jump(p1, p2, i1, i2, i3)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_duplicate_setfield_guard_value_const(self):
+ ops = """
+ [p1, i1, i2]
+ guard_value(p1, ConstPtr(myptr)) []
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ expected = """
+ [i1, i2]
+ setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+ jump(i1, i2)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected)
+
+ def test_duplicate_getarrayitem_1(self):
+ ops = """
+ [p1]
+ p2 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p3 = getarrayitem_gc(p1, 1, descr=arraydescr2)
+ p4 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p5 = getarrayitem_gc(p1, 1, descr=arraydescr2)
+ escape(p2)
+ escape(p3)
+ escape(p4)
+ escape(p5)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ p2 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p3 = getarrayitem_gc(p1, 1, descr=arraydescr2)
+ escape(p2)
+ escape(p3)
+ escape(p2)
+ escape(p3)
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getarrayitem_after_setarrayitem_1(self):
+ ops = """
+ [p1, p2]
+ setarrayitem_gc(p1, 0, p2, descr=arraydescr2)
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ escape(p3)
+ jump(p1, p3)
+ """
+ expected = """
+ [p1, p2]
+ setarrayitem_gc(p1, 0, p2, descr=arraydescr2)
+ escape(p2)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getarrayitem_after_setarrayitem_2(self):
+ ops = """
+ [p1, p2, p3, i1]
+ setarrayitem_gc(p1, 0, p2, descr=arraydescr2)
+ setarrayitem_gc(p1, i1, p3, descr=arraydescr2)
+ p4 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p5 = getarrayitem_gc(p1, i1, descr=arraydescr2)
+ escape(p4)
+ escape(p5)
+ jump(p1, p2, p3, i1)
+ """
+ expected = """
+ [p1, p2, p3, i1]
+ setarrayitem_gc(p1, 0, p2, descr=arraydescr2)
+ setarrayitem_gc(p1, i1, p3, descr=arraydescr2)
+ p4 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ escape(p4)
+ escape(p3)
+ jump(p1, p2, p3, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getarrayitem_after_setarrayitem_3(self):
+ ops = """
+ [p1, p2, p3, p4, i1]
+ setarrayitem_gc(p1, i1, p2, descr=arraydescr2)
+ setarrayitem_gc(p1, 0, p3, descr=arraydescr2)
+ setarrayitem_gc(p1, 1, p4, descr=arraydescr2)
+ p5 = getarrayitem_gc(p1, i1, descr=arraydescr2)
+ p6 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p7 = getarrayitem_gc(p1, 1, descr=arraydescr2)
+ escape(p5)
+ escape(p6)
+ escape(p7)
+ jump(p1, p2, p3, p4, i1)
+ """
+ expected = """
+ [p1, p2, p3, p4, i1]
+ setarrayitem_gc(p1, i1, p2, descr=arraydescr2)
+ setarrayitem_gc(p1, 0, p3, descr=arraydescr2)
+ setarrayitem_gc(p1, 1, p4, descr=arraydescr2)
+ p5 = getarrayitem_gc(p1, i1, descr=arraydescr2)
+ escape(p5)
+ escape(p3)
+ escape(p4)
+ jump(p1, p2, p3, p4, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_getarrayitem_pure_does_not_invalidate(self):
+ ops = """
+ [p1, p2]
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ i4 = getfield_gc_pure(ConstPtr(myptr), descr=valuedescr)
+ p5 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ escape(p3)
+ escape(i4)
+ escape(p5)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ escape(p3)
+ escape(5)
+ escape(p3)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_getarrayitem_after_setarrayitem_two_arrays(self):
+ ops = """
+ [p1, p2, p3, p4, i1]
+ setarrayitem_gc(p1, 0, p3, descr=arraydescr2)
+ setarrayitem_gc(p2, 1, p4, descr=arraydescr2)
+ p5 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p6 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ escape(p5)
+ escape(p6)
+ jump(p1, p2, p3, p4, i1)
+ """
+ expected = """
+ [p1, p2, p3, p4, i1]
+ setarrayitem_gc(p1, 0, p3, descr=arraydescr2)
+ setarrayitem_gc(p2, 1, p4, descr=arraydescr2)
+ escape(p3)
+ escape(p4)
+ jump(p1, p2, p3, p4, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bug_1(self):
+ ops = """
+ [i0, p1]
+ p4 = getfield_gc(p1, descr=nextdescr)
+ guard_nonnull(p4) []
+ escape(p4)
+ #
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ p3 = escape()
+ setfield_gc(p2, p3, descr=nextdescr)
+ jump(i0, p2)
+ """
+ expected = """
+ [i0, p4]
+ guard_nonnull(p4) []
+ escape(p4)
+ #
+ p3 = escape()
+ jump(i0, p3)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, Virtual(node_vtable, nextdescr=Not)',
+ expected)
+
+ def test_bug_2(self):
+ ops = """
+ [i0, p1]
+ p4 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ guard_nonnull(p4) []
+ escape(p4)
+ #
+ p2 = new_array(1, descr=arraydescr2)
+ p3 = escape()
+ setarrayitem_gc(p2, 0, p3, descr=arraydescr2)
+ jump(i0, p2)
+ """
+ expected = """
+ [i0, p4]
+ guard_nonnull(p4) []
+ escape(p4)
+ #
+ p3 = escape()
+ jump(i0, p3)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Not, VArray(arraydescr2, Not)',
+ expected)
+
+ def test_bug_3(self):
+ ops = """
+ [p1]
+ guard_nonnull(p1) []
+ guard_class(p1, ConstClass(node_vtable2)) []
+ p2 = getfield_gc(p1, descr=nextdescr)
+ guard_nonnull(12) []
+ guard_class(p2, ConstClass(node_vtable)) []
+ p3 = getfield_gc(p1, descr=otherdescr)
+ guard_nonnull(12) []
+ guard_class(p3, ConstClass(node_vtable)) []
+ setfield_gc(p3, p2, descr=otherdescr)
+ p1a = new_with_vtable(ConstClass(node_vtable2))
+ p2a = new_with_vtable(ConstClass(node_vtable))
+ p3a = new_with_vtable(ConstClass(node_vtable))
+ escape(p3a)
+ setfield_gc(p1a, p2a, descr=nextdescr)
+ setfield_gc(p1a, p3a, descr=otherdescr)
+ jump(p1a)
+ """
+ expected = """
+ [p2, p3]
+ guard_class(p2, ConstClass(node_vtable)) []
+ 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)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected)
+
+ def test_bug_3bis(self):
+ ops = """
+ [p1]
+ guard_nonnull(p1) []
+ guard_class(p1, ConstClass(node_vtable2)) []
+ p2 = getfield_gc(p1, descr=nextdescr)
+ guard_nonnull(12) []
+ guard_class(p2, ConstClass(node_vtable)) []
+ p3 = getfield_gc(p1, descr=otherdescr)
+ guard_nonnull(12) []
+ 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(p1a)
+ """
+ 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)
+ """
+ py.test.skip("XXX")
+ self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected)
+
+ def test_invalid_loop_1(self):
+ ops = """
+ [p1]
+ guard_isnull(p1) []
+ #
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ jump(p2)
+ """
+ py.test.skip("XXX")
+ py.test.raises(InvalidLoop, self.optimize_loop,
+ ops, 'Virtual(node_vtable)', None)
+
+ 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)) []
+ #
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ escape(p2) # prevent it from staying Virtual
+ jump(p2)
+ """
+ py.test.raises(InvalidLoop, self.optimize_loop,
+ ops, '...', None)
+
+ def test_invalid_loop_3(self):
+ ops = """
+ [p1]
+ p2 = getfield_gc(p1, descr=nextdescr)
+ guard_isnull(p2) []
+ #
+ p3 = new_with_vtable(ConstClass(node_vtable))
+ p4 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p3, p4, descr=nextdescr)
+ jump(p3)
+ """
+ py.test.skip("XXX")
+ py.test.raises(InvalidLoop, self.optimize_loop, ops,
+ 'Virtual(node_vtable, nextdescr=Virtual(node_vtable))',
+ None)
+
+ def test_merge_guard_class_guard_value(self):
+ ops = """
+ [p1, i0, i1, i2, p2]
+ guard_class(p1, ConstClass(node_vtable)) [i0]
+ i3 = int_add(i1, i2)
+ guard_value(p1, ConstPtr(myptr)) [i1]
+ jump(p2, i0, i1, i3, p2)
+ """
+ expected = """
+ [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, expected)
+
+ def test_merge_guard_nonnull_guard_class(self):
+ self.make_fail_descr()
+ ops = """
+ [p1, i0, i1, i2, p2]
+ guard_nonnull(p1, descr=fdescr) [i0]
+ i3 = int_add(i1, i2)
+ guard_class(p1, ConstClass(node_vtable)) [i1]
+ jump(p2, i0, i1, i3, p2)
+ """
+ expected = """
+ [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, expected)
+ 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]
+ i3 = int_add(i1, i2)
+ guard_value(p1, ConstPtr(myptr)) [i1]
+ jump(p2, i0, i1, i3, p2)
+ """
+ expected = """
+ [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, expected)
+ 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]
+ i3 = int_add(i1, i2)
+ guard_class(p1, ConstClass(node_vtable)) [i2]
+ i4 = int_sub(i3, 1)
+ guard_value(p1, ConstPtr(myptr)) [i1]
+ jump(p2, i0, i1, i4, p2)
+ """
+ expected = """
+ [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, expected)
+ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
+
+ def test_guard_class_oois(self):
+ ops = """
+ [p1]
+ guard_class(p1, ConstClass(node_vtable2)) []
+ i = ptr_ne(ConstPtr(myptr), p1)
+ guard_true(i) []
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ guard_class(p1, ConstClass(node_vtable2)) []
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_oois_of_itself(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ p2 = getfield_gc(p0, descr=nextdescr)
+ i1 = ptr_eq(p1, p2)
+ guard_true(i1) []
+ i2 = ptr_ne(p1, p2)
+ guard_false(i2) []
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_duplicate_pure_op(self):
+ ops = """
+ [p1, p2]
+ i1 = ptr_eq(p1, p2)
+ i2 = ptr_eq(p1, p2)
+ i3 = int_add(i1, 1)
+ i3b = int_is_true(i3)
+ guard_true(i3b) []
+ i4 = int_add(i2, 1)
+ i4b = int_is_true(i4)
+ guard_true(i4b) []
+ escape(i3)
+ escape(i4)
+ guard_true(i1) []
+ guard_true(i2) []
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = ptr_eq(p1, p2)
+ i3 = int_add(i1, 1)
+ i3b = int_is_true(i3)
+ guard_true(i3b) []
+ escape(i3)
+ escape(i3)
+ guard_true(i1) []
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_duplicate_pure_op_with_descr(self):
+ ops = """
+ [p1]
+ i0 = arraylen_gc(p1, descr=arraydescr)
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ i2 = arraylen_gc(p1, descr=arraydescr)
+ i3 = int_gt(i0, 0)
+ guard_true(i3) []
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = arraylen_gc(p1, descr=arraydescr)
+ i1 = int_gt(i0, 0)
+ guard_true(i1) []
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_remove_duplicate_pure_op_ovf(self):
+ ops = """
+ [i1]
+ i3 = int_add_ovf(i1, 1)
+ guard_no_overflow() []
+ i3b = int_is_true(i3)
+ guard_true(i3b) []
+ i4 = int_add_ovf(i1, 1)
+ guard_no_overflow() []
+ i4b = int_is_true(i4)
+ guard_true(i4b) []
+ escape(i3)
+ escape(i4)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ i3 = int_add_ovf(i1, 1)
+ guard_no_overflow() []
+ i3b = int_is_true(i3)
+ guard_true(i3b) []
+ escape(i3)
+ escape(i3)
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_and_or_with_zero(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 0)
+ i3 = int_and(0, i2)
+ i4 = int_or(i2, i1)
+ i5 = int_or(i0, i3)
+ jump(i4, i5)
+ """
+ expected = """
+ [i0, i1]
+ jump(i1, i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_fold_partially_constant_ops(self):
+ ops = """
+ [i0]
+ i1 = int_sub(i0, 0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ ops = """
+ [i0]
+ i1 = int_add(i0, 0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ ops = """
+ [i0]
+ i1 = int_add(0, i0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_fold_partially_constant_ops_ovf(self):
+ ops = """
+ [i0]
+ i1 = int_sub_ovf(i0, 0)
+ guard_no_overflow() []
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ ops = """
+ [i0]
+ i1 = int_add_ovf(i0, 0)
+ guard_no_overflow() []
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ ops = """
+ [i0]
+ i1 = int_add_ovf(0, i0)
+ guard_no_overflow() []
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ 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, 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, 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, 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, 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, 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)
+ """
+ py.test.skip("XXX")
+ 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, 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, 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)
+ """
+ py.test.skip("XXX")
+ 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, 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, expected)
+ self.check_expanded_fail_descr('''
+ ConstPtr(myptr).nextdescr = p2
+ where p2 is a node_vtable, valuedescr=i2
+ ''', rop.GUARD_TRUE)
+
+
+class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
+
+ def test_residual_call_does_not_invalidate_caches(self):
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = call(i1, descr=nonwritedescr)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ escape(i1)
+ escape(i3)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=valuedescr)
+ i2 = call(i1, descr=nonwritedescr)
+ escape(i1)
+ escape(i1)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_residual_call_invalidate_some_caches(self):
+ ops = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=adescr)
+ i2 = getfield_gc(p1, descr=bdescr)
+ i3 = call(i1, descr=writeadescr)
+ i4 = getfield_gc(p1, descr=adescr)
+ i5 = getfield_gc(p1, descr=bdescr)
+ escape(i1)
+ escape(i2)
+ escape(i4)
+ escape(i5)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = getfield_gc(p1, descr=adescr)
+ i2 = getfield_gc(p1, descr=bdescr)
+ i3 = call(i1, descr=writeadescr)
+ i4 = getfield_gc(p1, descr=adescr)
+ escape(i1)
+ escape(i2)
+ escape(i4)
+ escape(i2)
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_residual_call_invalidate_arrays(self):
+ ops = """
+ [p1, p2, i1]
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p4 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ i3 = call(i1, descr=writeadescr)
+ p5 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p6 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ escape(p3)
+ escape(p4)
+ escape(p5)
+ escape(p6)
+ jump(p1, p2, i1)
+ """
+ expected = """
+ [p1, p2, i1]
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p4 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ i3 = call(i1, descr=writeadescr)
+ escape(p3)
+ escape(p4)
+ escape(p3)
+ escape(p4)
+ jump(p1, p2, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_residual_call_invalidate_some_arrays(self):
+ ops = """
+ [p1, p2, i1]
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p4 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
+ i3 = call(i1, descr=writearraydescr)
+ p5 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p6 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ i4 = getarrayitem_gc(p1, 1, descr=arraydescr)
+ escape(p3)
+ escape(p4)
+ escape(p5)
+ escape(p6)
+ escape(i2)
+ escape(i4)
+ jump(p1, p2, i1)
+ """
+ expected = """
+ [p1, p2, i1]
+ p3 = getarrayitem_gc(p1, 0, descr=arraydescr2)
+ p4 = getarrayitem_gc(p2, 1, descr=arraydescr2)
+ i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
+ i3 = call(i1, descr=writearraydescr)
+ i4 = getarrayitem_gc(p1, 1, descr=arraydescr)
+ escape(p3)
+ escape(p4)
+ escape(p3)
+ escape(p4)
+ escape(i2)
+ escape(i4)
+ jump(p1, p2, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_residual_call_invalidates_some_read_caches_1(self):
+ ops = """
+ [p1, i1, p2, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=readadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ expected = """
+ [p1, i1, p2, i2]
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=readadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_residual_call_invalidates_some_read_caches_2(self):
+ ops = """
+ [p1, i1, p2, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=writeadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ expected = """
+ [p1, i1, p2, i2]
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=writeadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_residual_call_invalidates_some_read_caches_3(self):
+ ops = """
+ [p1, i1, p2, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=plaincalldescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_call_assembler_invalidates_caches(self):
+ ops = '''
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call_assembler(i1, descr=asmdescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ jump(p1, i3)
+ '''
+ self.optimize_loop(ops, ops)
+
+ def test_call_pure_invalidates_caches(self):
+ # CALL_PURE should still force the setfield_gc() to occur before it
+ ops = '''
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call_pure(42, p1, descr=plaincalldescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ jump(p1, i3)
+ '''
+ expected = '''
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call(p1, descr=plaincalldescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ jump(p1, i3)
+ '''
+ 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
+ # to call the function arbitrary many times at arbitrary points in
+ # 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.
+ ops = '''
+ [i0, i1, i2]
+ escape(i1)
+ escape(i2)
+ i3 = call_pure(42, 123456, 4, 5, 6, descr=plaincalldescr)
+ i4 = call_pure(43, 123456, 4, i0, 6, descr=plaincalldescr)
+ jump(i0, i3, i4)
+ '''
+ expected = '''
+ [i0, i1, i2]
+ escape(i1)
+ escape(i2)
+ i4 = call(123456, 4, i0, 6, descr=plaincalldescr)
+ jump(i0, 42, i4)
+ '''
+ self.optimize_loop(ops, expected)
+
+ def test_vref_nonvirtual_nonescape(self):
+ ops = """
+ [p1]
+ p2 = virtual_ref(p1, 5)
+ virtual_ref_finish(p2, p1)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = force_token()
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_vref_nonvirtual_escape(self):
+ ops = """
+ [p1]
+ p2 = virtual_ref(p1, 5)
+ escape(p2)
+ virtual_ref_finish(p2, p1)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = force_token()
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i0, descr=virtualtokendescr)
+ setfield_gc(p2, 5, descr=virtualrefindexdescr)
+ escape(p2)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, -3, descr=virtualtokendescr)
+ jump(p1)
+ """
+ # 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, expected)
+
+ def test_vref_virtual_1(self):
+ ops = """
+ [p0, i1]
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, 252, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ #
+ p2 = virtual_ref(p1, 3)
+ setfield_gc(p0, p2, descr=nextdescr)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() [i1]
+ virtual_ref_finish(p2, p1)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ #
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i3, descr=virtualtokendescr)
+ setfield_gc(p2, 3, descr=virtualrefindexdescr)
+ setfield_gc(p0, p2, descr=nextdescr)
+ #
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() [i1]
+ #
+ setfield_gc(p0, NULL, descr=nextdescr)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, 252, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, -3, descr=virtualtokendescr)
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_vref_virtual_2(self):
+ self.make_fail_descr()
+ ops = """
+ [p0, i1]
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, i1, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ #
+ p2 = virtual_ref(p1, 2)
+ setfield_gc(p0, p2, descr=nextdescr)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced(descr=fdescr) [p2, p1]
+ virtual_ref_finish(p2, p1)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ #
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i3, descr=virtualtokendescr)
+ setfield_gc(p2, 2, descr=virtualrefindexdescr)
+ setfield_gc(p0, p2, descr=nextdescr)
+ #
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced(descr=fdescr) [p2, i1]
+ #
+ setfield_gc(p0, NULL, descr=nextdescr)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, i1, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, -3, descr=virtualtokendescr)
+ jump(p0, i1)
+ """
+ # 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, 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]
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, i1, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ #
+ p2 = virtual_ref(p1, 2)
+ setfield_gc(p0, p2, descr=refdescr)
+ call(i1, descr=nonwritedescr)
+ guard_no_exception(descr=fdescr) [p2, p1]
+ virtual_ref_finish(p2, p1)
+ setfield_gc(p0, NULL, descr=refdescr)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ call(i1, descr=nonwritedescr)
+ guard_no_exception(descr=fdescr) [i3, i1, p0]
+ setfield_gc(p0, NULL, descr=refdescr)
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, expected)
+ # 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)
+
+ def test_vref_virtual_after_finish(self):
+ self.make_fail_descr()
+ ops = """
+ [i1]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p2 = virtual_ref(p1, 7)
+ escape(p2)
+ virtual_ref_finish(p2, p1)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() []
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ i3 = force_token()
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i3, descr=virtualtokendescr)
+ setfield_gc(p2, 7, descr=virtualrefindexdescr)
+ escape(p2)
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, -3, descr=virtualtokendescr)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() []
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_vref_nonvirtual_and_lazy_setfield(self):
+ self.make_fail_descr()
+ ops = """
+ [i1, p1]
+ p2 = virtual_ref(p1, 23)
+ escape(p2)
+ virtual_ref_finish(p2, p1)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() [i1]
+ jump(i1, p1)
+ """
+ expected = """
+ [i1, p1]
+ i3 = force_token()
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i3, descr=virtualtokendescr)
+ setfield_gc(p2, 23, descr=virtualrefindexdescr)
+ escape(p2)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, -3, descr=virtualtokendescr)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() [i1]
+ jump(i1, p1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_arraycopy_1(self):
+ ops = '''
+ [i0]
+ p1 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p1, 1, 1, descr=arraydescr)
+ p2 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p2, 1, 3, descr=arraydescr)
+ call(0, p1, p2, 1, 1, 2, descr=arraycopydescr)
+ i2 = getarrayitem_gc(p2, 1, descr=arraydescr)
+ jump(i2)
+ '''
+ expected = '''
+ [i0]
+ jump(1)
+ '''
+ self.optimize_loop(ops, expected)
+
+ def test_arraycopy_2(self):
+ ops = '''
+ [i0]
+ p1 = new_array(3, descr=arraydescr)
+ p2 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i0, descr=arraydescr)
+ setarrayitem_gc(p2, 0, 3, descr=arraydescr)
+ call(0, p1, p2, 1, 1, 2, descr=arraycopydescr)
+ i2 = getarrayitem_gc(p2, 0, descr=arraydescr)
+ jump(i2)
+ '''
+ expected = '''
+ [i0]
+ jump(3)
+ '''
+ 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)
+ '''
+ expected = '''
+ [p0]
+ p2 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p2, 2, 10, descr=arraydescr)
+ jump(p2)
+ '''
+ self.optimize_loop(ops, expected)
+
+ def test_arraycopy_no_elem(self):
+ """ this was actually observed in the wild
+ """
+ ops = '''
+ [p1]
+ p0 = new_array(0, descr=arraydescr)
+ call(0, p0, p1, 0, 0, 0, descr=arraycopydescr)
+ jump(p1)
+ '''
+ expected = '''
+ [p1]
+ jump(p1)
+ '''
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_lt(i0, 5)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_noguard(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ i2 = int_lt(i0, 5)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ i2 = int_lt(i0, 5)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_noopt(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_false(i1) []
+ i2 = int_lt(i0, 5)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_false(i1) []
+ i2 = int_lt(i0, 5)
+ guard_true(i2) []
+ jump(4)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_rev(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_false(i1) []
+ i2 = int_gt(i0, 3)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_false(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_tripple(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 0)
+ guard_true(i1) []
+ i2 = int_lt(i0, 7)
+ guard_true(i2) []
+ i3 = int_lt(i0, 5)
+ guard_true(i3) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 0)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_add(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_add(i0, 10)
+ i3 = int_lt(i2, 15)
+ guard_true(i3) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_add(i0, 10)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_add_before(self):
+ ops = """
+ [i0]
+ i2 = int_add(i0, 10)
+ i3 = int_lt(i2, 15)
+ guard_true(i3) []
+ i1 = int_lt(i0, 6)
+ guard_true(i1) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i2 = int_add(i0, 10)
+ i3 = int_lt(i2, 15)
+ guard_true(i3) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_add_ovf(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_add_ovf(i0, 10)
+ guard_no_overflow() []
+ i3 = int_lt(i2, 15)
+ guard_true(i3) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_add(i0, 10)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_add_ovf_before(self):
+ ops = """
+ [i0]
+ i2 = int_add_ovf(i0, 10)
+ guard_no_overflow() []
+ i3 = int_lt(i2, 15)
+ guard_true(i3) []
+ i1 = int_lt(i0, 6)
+ guard_true(i1) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i2 = int_add_ovf(i0, 10)
+ guard_no_overflow() []
+ i3 = int_lt(i2, 15)
+ guard_true(i3) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_sub(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_sub(i0, 10)
+ i3 = int_lt(i2, -5)
+ guard_true(i3) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_sub(i0, 10)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lt_sub_before(self):
+ ops = """
+ [i0]
+ i2 = int_sub(i0, 10)
+ i3 = int_lt(i2, -5)
+ guard_true(i3) []
+ i1 = int_lt(i0, 5)
+ guard_true(i1) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i2 = int_sub(i0, 10)
+ i3 = int_lt(i2, -5)
+ guard_true(i3) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_ltle(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ i2 = int_le(i0, 3)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 4)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lelt(self):
+ ops = """
+ [i0]
+ i1 = int_le(i0, 4)
+ guard_true(i1) []
+ i2 = int_lt(i0, 5)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_le(i0, 4)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_gt(self):
+ ops = """
+ [i0]
+ i1 = int_gt(i0, 5)
+ guard_true(i1) []
+ i2 = int_gt(i0, 4)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_gt(i0, 5)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_gtge(self):
+ ops = """
+ [i0]
+ i1 = int_gt(i0, 5)
+ guard_true(i1) []
+ i2 = int_ge(i0, 6)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_gt(i0, 5)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_gegt(self):
+ ops = """
+ [i0]
+ i1 = int_ge(i0, 5)
+ guard_true(i1) []
+ i2 = int_gt(i0, 4)
+ guard_true(i2) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_ge(i0, 5)
+ guard_true(i1) []
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_ovf(self):
+ ops = """
+ [i0]
+ i1 = int_ge(i0, 0)
+ guard_true(i1) []
+ i2 = int_lt(i0, 10)
+ guard_true(i2) []
+ i3 = int_add_ovf(i0, 1)
+ guard_no_overflow() []
+ jump(i3)
+ """
+ expected = """
+ [i0]
+ i1 = int_ge(i0, 0)
+ guard_true(i1) []
+ i2 = int_lt(i0, 10)
+ guard_true(i2) []
+ i3 = int_add(i0, 1)
+ jump(i3)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_arraylen(self):
+ ops = """
+ [i0, p0]
+ p1 = new_array(i0, descr=arraydescr)
+ i1 = arraylen_gc(p1)
+ i2 = int_gt(i1, -1)
+ guard_true(i2) []
+ setarrayitem_gc(p0, 0, p1)
+ jump(i0, p0)
+ """
+ # The dead arraylen_gc will be eliminated by the backend.
+ expected = """
+ [i0, p0]
+ p1 = new_array(i0, descr=arraydescr)
+ i1 = arraylen_gc(p1)
+ setarrayitem_gc(p0, 0, p1)
+ jump(i0, p0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_strlen(self):
+ ops = """
+ [p0]
+ i0 = strlen(p0)
+ i1 = int_ge(i0, 0)
+ guard_true(i1) []
+ jump(p0)
+ """
+ # The dead strlen will be eliminated be the backend.
+ expected = """
+ [p0]
+ i0 = strlen(p0)
+ jump(p0)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_addsub_const(self):
+ ops = """
+ [i0]
+ i1 = int_add(i0, 1)
+ i2 = int_sub(i1, 1)
+ i3 = int_add(i2, 1)
+ i4 = int_mul(i2, i3)
+ jump(i4)
+ """
+ expected = """
+ [i0]
+ i1 = int_add(i0, 1)
+ i4 = int_mul(i0, i1)
+ jump(i4)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_addsub_int(self):
+ ops = """
+ [i0, i10]
+ i1 = int_add(i0, i10)
+ i2 = int_sub(i1, i10)
+ i3 = int_add(i2, i10)
+ i4 = int_add(i2, i3)
+ jump(i4, i10)
+ """
+ expected = """
+ [i0, i10]
+ i1 = int_add(i0, i10)
+ i4 = int_add(i0, i1)
+ jump(i4, i10)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_addsub_int2(self):
+ ops = """
+ [i0, i10]
+ i1 = int_add(i10, i0)
+ i2 = int_sub(i1, i10)
+ i3 = int_add(i10, i2)
+ i4 = int_add(i2, i3)
+ jump(i4, i10)
+ """
+ expected = """
+ [i0, i10]
+ i1 = int_add(i10, i0)
+ i4 = int_add(i0, i1)
+ jump(i4, i10)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_framestackdepth_overhead(self):
+ ops = """
+ [p0, i22]
+ i1 = getfield_gc(p0, descr=valuedescr)
+ i2 = int_gt(i1, i22)
+ guard_false(i2) []
+ i3 = int_add(i1, 1)
+ setfield_gc(p0, i3, descr=valuedescr)
+ i4 = int_sub(i3, 1)
+ setfield_gc(p0, i4, descr=valuedescr)
+ i5 = int_gt(i4, i22)
+ guard_false(i5) []
+ i6 = int_add(i4, 1)
+ i331 = force_token()
+ i7 = int_sub(i6, 1)
+ setfield_gc(p0, i7, descr=valuedescr)
+ 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)
+ i331 = force_token()
+ setfield_gc(p0, i1, descr=valuedescr)
+ jump(p0, i22)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_addsub_ovf(self):
+ ops = """
+ [i0]
+ i1 = int_add_ovf(i0, 10)
+ guard_no_overflow() []
+ i2 = int_sub_ovf(i1, 5)
+ guard_no_overflow() []
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_add_ovf(i0, 10)
+ guard_no_overflow() []
+ i2 = int_sub(i1, 5)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_subadd_ovf(self):
+ ops = """
+ [i0]
+ i1 = int_sub_ovf(i0, 10)
+ guard_no_overflow() []
+ i2 = int_add_ovf(i1, 5)
+ guard_no_overflow() []
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_sub_ovf(i0, 10)
+ guard_no_overflow() []
+ i2 = int_add(i1, 5)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_and(self):
+ ops = """
+ [i0]
+ i1 = int_and(i0, 255)
+ i2 = int_lt(i1, 500)
+ guard_true(i2) []
+ i3 = int_le(i1, 255)
+ guard_true(i3) []
+ i4 = int_gt(i1, -1)
+ guard_true(i4) []
+ i5 = int_ge(i1, 0)
+ guard_true(i5) []
+ i6 = int_lt(i1, 0)
+ guard_false(i6) []
+ i7 = int_le(i1, -1)
+ guard_false(i7) []
+ i8 = int_gt(i1, 255)
+ guard_false(i8) []
+ i9 = int_ge(i1, 500)
+ guard_false(i9) []
+ i12 = int_lt(i1, 100)
+ guard_true(i12) []
+ i13 = int_le(i1, 90)
+ guard_true(i13) []
+ i14 = int_gt(i1, 10)
+ guard_true(i14) []
+ i15 = int_ge(i1, 20)
+ guard_true(i15) []
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ i1 = int_and(i0, 255)
+ i12 = int_lt(i1, 100)
+ guard_true(i12) []
+ i13 = int_le(i1, 90)
+ guard_true(i13) []
+ i14 = int_gt(i1, 10)
+ guard_true(i14) []
+ i15 = int_ge(i1, 20)
+ guard_true(i15) []
+ jump(i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_subsub_ovf(self):
+ ops = """
+ [i0]
+ i1 = int_sub_ovf(1, i0)
+ guard_no_overflow() []
+ i2 = int_gt(i1, 1)
+ guard_true(i2) []
+ i3 = int_sub_ovf(1, i0)
+ guard_no_overflow() []
+ i4 = int_gt(i3, 1)
+ guard_true(i4) []
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ i1 = int_sub_ovf(1, i0)
+ guard_no_overflow() []
+ i2 = int_gt(i1, 1)
+ guard_true(i2) []
+ i3 = int_sub(1, i0)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_eq(self):
+ ops = """
+ [i0, i1]
+ 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]
+ i2 = int_le(i0, 4)
+ guard_true(i2) []
+ i3 = int_eq(i0, i1)
+ guard_true(i3) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_eq_const(self):
+ ops = """
+ [i0]
+ i1 = int_eq(i0, 7)
+ guard_true(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_eq(i0, 7)
+ guard_true(i1) []
+ jump(10)
+
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_eq_const_not(self):
+ ops = """
+ [i0]
+ i1 = int_eq(i0, 7)
+ guard_false(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_eq(i0, 7)
+ guard_false(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_ne_const(self):
+ ops = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_false(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_false(i1) []
+ jump(10)
+
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_ne_const_not(self):
+ ops = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_true(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_true(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_ltne(self):
+ ops = """
+ [i0, i1]
+ i2 = int_lt(i0, 7)
+ guard_true(i2) []
+ i3 = int_ne(i0, 10)
+ guard_true(i2) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_lt(i0, 7)
+ guard_true(i2) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_bound_lege_const(self):
+ ops = """
+ [i0]
+ i1 = int_ge(i0, 7)
+ guard_true(i1) []
+ i2 = int_le(i0, 7)
+ guard_true(i2) []
+ i3 = int_add(i0, 3)
+ jump(i3)
+ """
+ expected = """
+ [i0]
+ i1 = int_ge(i0, 7)
+ guard_true(i1) []
+ i2 = int_le(i0, 7)
+ guard_true(i2) []
+ jump(10)
+
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_mul_ovf(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_lt(i1, 5)
+ guard_true(i3) []
+ i4 = int_gt(i1, -10)
+ guard_true(i4) []
+ i5 = int_mul_ovf(i2, i1)
+ guard_no_overflow() []
+ i6 = int_lt(i5, -2550)
+ guard_false(i6) []
+ i7 = int_ge(i5, 1276)
+ guard_false(i7) []
+ i8 = int_gt(i5, 126)
+ guard_true(i8) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_lt(i1, 5)
+ guard_true(i3) []
+ i4 = int_gt(i1, -10)
+ guard_true(i4) []
+ i5 = int_mul(i2, i1)
+ i8 = int_gt(i5, 126)
+ guard_true(i8) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_mul_ovf_before(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i22 = int_add(i2, 1)
+ i3 = int_mul_ovf(i22, i1)
+ guard_no_overflow() []
+ i4 = int_lt(i3, 10)
+ guard_true(i4) []
+ i5 = int_gt(i3, 2)
+ guard_true(i5) []
+ i6 = int_lt(i1, 0)
+ guard_false(i6) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i22 = int_add(i2, 1)
+ i3 = int_mul_ovf(i22, i1)
+ guard_no_overflow() []
+ i4 = int_lt(i3, 10)
+ guard_true(i4) []
+ i5 = int_gt(i3, 2)
+ guard_true(i5) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_sub_ovf_before(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_sub_ovf(i2, i1)
+ guard_no_overflow() []
+ i4 = int_le(i3, 10)
+ guard_true(i4) []
+ i5 = int_ge(i3, 2)
+ guard_true(i5) []
+ i6 = int_lt(i1, -10)
+ guard_false(i6) []
+ i7 = int_gt(i1, 253)
+ guard_false(i7) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_sub_ovf(i2, i1)
+ guard_no_overflow() []
+ i4 = int_le(i3, 10)
+ guard_true(i4) []
+ i5 = int_ge(i3, 2)
+ guard_true(i5) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ # ----------
+ def optimize_strunicode_loop(self, ops, optops):
+ # check with the arguments passed in
+ self.optimize_loop(ops, optops)
+ # check with replacing 'str' with 'unicode' everywhere
+ self.optimize_loop(ops.replace('str','unicode').replace('s"', 'u"'),
+ optops.replace('str','unicode').replace('s"', 'u"'))
+
+ def test_newstr_1(self):
+ ops = """
+ [i0]
+ p1 = newstr(1)
+ strsetitem(p1, 0, i0)
+ i1 = strgetitem(p1, 0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_newstr_2(self):
+ ops = """
+ [i0, i1]
+ p1 = newstr(2)
+ strsetitem(p1, 0, i0)
+ strsetitem(p1, 1, i1)
+ i2 = strgetitem(p1, 1)
+ i3 = strgetitem(p1, 0)
+ jump(i2, i3)
+ """
+ expected = """
+ [i0, i1]
+ jump(i1, i0)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_concat_1(self):
+ ops = """
+ [p1, p2]
+ p3 = call(0, p1, p2, descr=strconcatdescr)
+ jump(p2, p3)
+ """
+ expected = """
+ [p1, p2]
+ i1 = strlen(p1)
+ i2 = strlen(p2)
+ i3 = int_add(i1, i2)
+ p3 = newstr(i3)
+ i4 = strlen(p1)
+ copystrcontent(p1, p3, 0, 0, i4)
+ i5 = strlen(p2)
+ i6 = int_add(i4, i5) # will be killed by the backend
+ copystrcontent(p2, p3, 0, i4, i5)
+ jump(p2, p3)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_concat_vstr2_str(self):
+ ops = """
+ [i0, i1, p2]
+ p1 = newstr(2)
+ strsetitem(p1, 0, i0)
+ strsetitem(p1, 1, i1)
+ p3 = call(0, p1, p2, descr=strconcatdescr)
+ jump(i1, i0, p3)
+ """
+ expected = """
+ [i0, i1, p2]
+ i2 = strlen(p2)
+ i3 = int_add(2, i2)
+ p3 = newstr(i3)
+ strsetitem(p3, 0, i0)
+ strsetitem(p3, 1, i1)
+ i4 = strlen(p2)
+ i5 = int_add(2, i4) # will be killed by the backend
+ copystrcontent(p2, p3, 0, 2, i4)
+ jump(i1, i0, p3)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_concat_str_vstr2(self):
+ ops = """
+ [i0, i1, p2]
+ p1 = newstr(2)
+ strsetitem(p1, 0, i0)
+ strsetitem(p1, 1, i1)
+ p3 = call(0, p2, p1, descr=strconcatdescr)
+ jump(i1, i0, p3)
+ """
+ expected = """
+ [i0, i1, p2]
+ i2 = strlen(p2)
+ i3 = int_add(i2, 2)
+ p3 = newstr(i3)
+ i4 = strlen(p2)
+ copystrcontent(p2, p3, 0, 0, i4)
+ strsetitem(p3, i4, i0)
+ i5 = int_add(i4, 1)
+ strsetitem(p3, i5, i1)
+ i6 = int_add(i5, 1) # will be killed by the backend
+ jump(i1, i0, p3)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_concat_str_str_str(self):
+ ops = """
+ [p1, p2, p3]
+ p4 = call(0, p1, p2, descr=strconcatdescr)
+ p5 = call(0, p4, p3, descr=strconcatdescr)
+ jump(p2, p3, p5)
+ """
+ expected = """
+ [p1, p2, p3]
+ i1 = strlen(p1)
+ i2 = strlen(p2)
+ i12 = int_add(i1, i2)
+ i3 = strlen(p3)
+ i123 = int_add(i12, i3)
+ p5 = newstr(i123)
+ i1b = strlen(p1)
+ copystrcontent(p1, p5, 0, 0, i1b)
+ i2b = strlen(p2)
+ i12b = int_add(i1b, i2b)
+ copystrcontent(p2, p5, 0, i1b, i2b)
+ i3b = strlen(p3)
+ i123b = int_add(i12b, i3b) # will be killed by the backend
+ copystrcontent(p3, p5, 0, i12b, i3b)
+ jump(p2, p3, p5)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_concat_str_cstr1(self):
+ ops = """
+ [p2]
+ p3 = call(0, p2, s"x", descr=strconcatdescr)
+ jump(p3)
+ """
+ expected = """
+ [p2]
+ i2 = strlen(p2)
+ i3 = int_add(i2, 1)
+ p3 = newstr(i3)
+ i4 = strlen(p2)
+ copystrcontent(p2, p3, 0, 0, i4)
+ strsetitem(p3, i4, 120) # == ord('x')
+ i5 = int_add(i4, 1) # will be killed by the backend
+ jump(p3)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_concat_consts(self):
+ ops = """
+ []
+ p1 = same_as(s"ab")
+ p2 = same_as(s"cde")
+ p3 = call(0, p1, p2, descr=strconcatdescr)
+ escape(p3)
+ jump()
+ """
+ expected = """
+ []
+ escape(s"abcde")
+ jump()
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_slice_1(self):
+ ops = """
+ [p1, i1, i2]
+ p2 = call(0, p1, i1, i2, descr=strslicedescr)
+ jump(p2, i1, i2)
+ """
+ expected = """
+ [p1, i1, i2]
+ i3 = int_sub(i2, i1)
+ p2 = newstr(i3)
+ copystrcontent(p1, p2, i1, 0, i3)
+ jump(p2, i1, i2)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_slice_2(self):
+ ops = """
+ [p1, i2]
+ p2 = call(0, p1, 0, i2, descr=strslicedescr)
+ jump(p2, i2)
+ """
+ expected = """
+ [p1, i2]
+ p2 = newstr(i2)
+ copystrcontent(p1, p2, 0, 0, i2)
+ jump(p2, i2)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_slice_3(self):
+ ops = """
+ [p1, i1, i2, i3, i4]
+ p2 = call(0, p1, i1, i2, descr=strslicedescr)
+ p3 = call(0, p2, i3, i4, descr=strslicedescr)
+ jump(p3, i1, i2, i3, i4)
+ """
+ expected = """
+ [p1, i1, i2, i3, i4]
+ i0 = int_sub(i2, i1) # killed by the backend
+ i5 = int_sub(i4, i3)
+ i6 = int_add(i1, i3)
+ p3 = newstr(i5)
+ copystrcontent(p1, p3, i6, 0, i5)
+ jump(p3, i1, i2, i3, i4)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_slice_getitem1(self):
+ ops = """
+ [p1, i1, i2, i3]
+ p2 = call(0, p1, i1, i2, descr=strslicedescr)
+ i4 = strgetitem(p2, i3)
+ escape(i4)
+ jump(p1, i1, i2, i3)
+ """
+ expected = """
+ [p1, i1, i2, i3]
+ i6 = int_sub(i2, i1) # killed by the backend
+ i5 = int_add(i1, i3)
+ i4 = strgetitem(p1, i5)
+ escape(i4)
+ jump(p1, i1, i2, i3)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_slice_plain(self):
+ ops = """
+ [i3, i4]
+ p1 = newstr(2)
+ strsetitem(p1, 0, i3)
+ strsetitem(p1, 1, i4)
+ p2 = call(0, p1, 1, 2, descr=strslicedescr)
+ i5 = strgetitem(p2, 0)
+ escape(i5)
+ jump(i3, i4)
+ """
+ expected = """
+ [i3, i4]
+ escape(i4)
+ jump(i3, i4)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ def test_str_slice_concat(self):
+ ops = """
+ [p1, i1, i2, p2]
+ p3 = call(0, p1, i1, i2, descr=strslicedescr)
+ p4 = call(0, p3, p2, descr=strconcatdescr)
+ jump(p4, i1, i2, p2)
+ """
+ expected = """
+ [p1, i1, i2, p2]
+ i3 = int_sub(i2, i1) # length of p3
+ i4 = strlen(p2)
+ i5 = int_add(i3, i4)
+ p4 = newstr(i5)
+ copystrcontent(p1, p4, i1, 0, i3)
+ i4b = strlen(p2)
+ i6 = int_add(i3, i4b) # killed by the backend
+ copystrcontent(p2, p4, 0, i3, i4b)
+ jump(p4, i1, i2, p2)
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
+ # ----------
+ def optimize_strunicode_loop_extradescrs(self, ops, optops):
+ from pypy.jit.metainterp.optimizeopt import string
+ class FakeCallInfoCollection:
+ def callinfo_for_oopspec(self, oopspecindex):
+ calldescrtype = type(LLtypeMixin.strequaldescr)
+ for value in LLtypeMixin.__dict__.values():
+ if isinstance(value, calldescrtype):
+ extra = value.get_extra_info()
+ if extra and extra.oopspecindex == oopspecindex:
+ # returns 0 for 'func' in this test
+ return value, 0
+ raise AssertionError("not found: oopspecindex=%d" %
+ oopspecindex)
+ #
+ self.callinfocollection = FakeCallInfoCollection()
+ self.optimize_strunicode_loop(ops, optops)
+
+ def test_str_equal_noop1(self):
+ ops = """
+ [p1, p2]
+ i0 = call(0, p1, p2, descr=strequaldescr)
+ escape(i0)
+ jump(p1, p2)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, ops)
+
+ def test_str_equal_noop2(self):
+ ops = """
+ [p1, p2, p3]
+ p4 = call(0, p1, p2, descr=strconcatdescr)
+ i0 = call(0, p3, p4, descr=strequaldescr)
+ escape(i0)
+ jump(p1, p2, p3)
+ """
+ expected = """
+ [p1, p2, p3]
+ i1 = strlen(p1)
+ i2 = strlen(p2)
+ i3 = int_add(i1, i2)
+ p4 = newstr(i3)
+ i4 = strlen(p1)
+ copystrcontent(p1, p4, 0, 0, i4)
+ i5 = strlen(p2)
+ i6 = int_add(i4, i5) # will be killed by the backend
+ copystrcontent(p2, p4, 0, i4, i5)
+ i0 = call(0, p3, p4, descr=strequaldescr)
+ escape(i0)
+ jump(p1, p2, p3)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_slice1(self):
+ ops = """
+ [p1, i1, i2, p3]
+ p4 = call(0, p1, i1, i2, descr=strslicedescr)
+ i0 = call(0, p4, p3, descr=strequaldescr)
+ escape(i0)
+ jump(p1, i1, i2, p3)
+ """
+ expected = """
+ [p1, i1, i2, p3]
+ i3 = int_sub(i2, i1)
+ i0 = call(0, p1, i1, i3, p3, descr=streq_slice_checknull_descr)
+ escape(i0)
+ jump(p1, i1, i2, p3)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_slice2(self):
+ ops = """
+ [p1, i1, i2, p3]
+ p4 = call(0, p1, i1, i2, descr=strslicedescr)
+ i0 = call(0, p3, p4, descr=strequaldescr)
+ escape(i0)
+ jump(p1, i1, i2, p3)
+ """
+ expected = """
+ [p1, i1, i2, p3]
+ i4 = int_sub(i2, i1)
+ i0 = call(0, p1, i1, i4, p3, descr=streq_slice_checknull_descr)
+ escape(i0)
+ jump(p1, i1, i2, p3)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_slice3(self):
+ ops = """
+ [p1, i1, i2, p3]
+ guard_nonnull(p3) []
+ p4 = call(0, p1, i1, i2, descr=strslicedescr)
+ i0 = call(0, p3, p4, descr=strequaldescr)
+ escape(i0)
+ jump(p1, i1, i2, p3)
+ """
+ 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, expected)
+
+ def test_str_equal_slice4(self):
+ ops = """
+ [p1, i1, i2]
+ p3 = call(0, p1, i1, i2, descr=strslicedescr)
+ i0 = call(0, p3, s"x", descr=strequaldescr)
+ escape(i0)
+ jump(p1, i1, i2)
+ """
+ expected = """
+ [p1, i1, i2]
+ i3 = int_sub(i2, i1)
+ i0 = call(0, p1, i1, i3, 120, descr=streq_slice_char_descr)
+ escape(i0)
+ jump(p1, i1, i2)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_slice5(self):
+ ops = """
+ [p1, i1, i2, i3]
+ p4 = call(0, p1, i1, i2, descr=strslicedescr)
+ p5 = newstr(1)
+ strsetitem(p5, 0, i3)
+ i0 = call(0, p5, p4, descr=strequaldescr)
+ escape(i0)
+ jump(p1, i1, i2, i3)
+ """
+ expected = """
+ [p1, i1, i2, i3]
+ i4 = int_sub(i2, i1)
+ i0 = call(0, p1, i1, i4, i3, descr=streq_slice_char_descr)
+ escape(i0)
+ jump(p1, i1, i2, i3)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_none1(self):
+ ops = """
+ [p1]
+ i0 = call(0, p1, NULL, descr=strequaldescr)
+ escape(i0)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = ptr_eq(p1, NULL)
+ escape(i0)
+ jump(p1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_none2(self):
+ ops = """
+ [p1]
+ i0 = call(0, NULL, p1, descr=strequaldescr)
+ escape(i0)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = ptr_eq(p1, NULL)
+ escape(i0)
+ jump(p1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_nonnull1(self):
+ ops = """
+ [p1]
+ guard_nonnull(p1) []
+ i0 = call(0, p1, s"hello world", descr=strequaldescr)
+ escape(i0)
+ jump(p1)
+ """
+ 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, expected)
+
+ def test_str_equal_nonnull2(self):
+ ops = """
+ [p1]
+ guard_nonnull(p1) []
+ i0 = call(0, p1, s"", descr=strequaldescr)
+ escape(i0)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ guard_nonnull(p1) []
+ i1 = strlen(p1)
+ i0 = int_eq(i1, 0)
+ escape(i0)
+ jump(p1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_nonnull3(self):
+ ops = """
+ [p1]
+ guard_nonnull(p1) []
+ i0 = call(0, p1, s"x", descr=strequaldescr)
+ escape(i0)
+ jump(p1)
+ """
+ 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, expected)
+
+ def test_str_equal_nonnull4(self):
+ ops = """
+ [p1, p2]
+ p4 = call(0, p1, p2, descr=strconcatdescr)
+ i0 = call(0, s"hello world", p4, descr=strequaldescr)
+ escape(i0)
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = strlen(p1)
+ i2 = strlen(p2)
+ i3 = int_add(i1, i2)
+ p4 = newstr(i3)
+ i4 = strlen(p1)
+ copystrcontent(p1, p4, 0, 0, i4)
+ i5 = strlen(p2)
+ i6 = int_add(i4, i5) # will be killed by the backend
+ copystrcontent(p2, p4, 0, i4, i5)
+ i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr)
+ escape(i0)
+ jump(p1, p2)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_chars0(self):
+ ops = """
+ [i1]
+ p1 = newstr(0)
+ i0 = call(0, p1, s"", descr=strequaldescr)
+ escape(i0)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ escape(1)
+ jump(i1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_chars1(self):
+ ops = """
+ [i1]
+ p1 = newstr(1)
+ strsetitem(p1, 0, i1)
+ i0 = call(0, p1, s"x", descr=strequaldescr)
+ escape(i0)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ i0 = int_eq(i1, 120) # ord('x')
+ escape(i0)
+ jump(i1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_chars2(self):
+ ops = """
+ [i1, i2]
+ p1 = newstr(2)
+ strsetitem(p1, 0, i1)
+ strsetitem(p1, 1, i2)
+ i0 = call(0, p1, s"xy", descr=strequaldescr)
+ escape(i0)
+ jump(i1, i2)
+ """
+ expected = """
+ [i1, i2]
+ p1 = newstr(2)
+ strsetitem(p1, 0, i1)
+ strsetitem(p1, 1, i2)
+ i0 = call(0, p1, s"xy", descr=streq_lengthok_descr)
+ escape(i0)
+ jump(i1, i2)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_chars3(self):
+ ops = """
+ [p1]
+ i0 = call(0, s"x", p1, descr=strequaldescr)
+ escape(i0)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = call(0, p1, 120, descr=streq_checknull_char_descr)
+ escape(i0)
+ jump(p1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str_equal_lengthmismatch1(self):
+ ops = """
+ [i1]
+ p1 = newstr(1)
+ strsetitem(p1, 0, i1)
+ i0 = call(0, s"xy", p1, descr=strequaldescr)
+ escape(i0)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ escape(0)
+ jump(i1)
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str2unicode_constant(self):
+ ops = """
+ []
+ p0 = call(0, "xy", descr=s2u_descr) # string -> unicode
+ escape(p0)
+ jump()
+ """
+ expected = """
+ []
+ escape(u"xy")
+ jump()
+ """
+ self.optimize_strunicode_loop_extradescrs(ops, expected)
+
+ def test_str2unicode_nonconstant(self):
+ ops = """
+ [p0]
+ p1 = call(0, p0, descr=s2u_descr) # string -> unicode
+ escape(p1)
+ jump(p1)
+ """
+ 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(BaseTestOptimizeBasic, OOtypeMixin):
+
+## def test_instanceof(self):
+## ops = """
+## [i0]
+## p0 = new_with_vtable(ConstClass(node_vtable))
+## i1 = instanceof(p0, descr=nodesize)
+## jump(i1)
+## """
+## expected = """
+## [i0]
+## jump(1)
+## """
+## self.optimize_loop(ops, expected)
+
+## def test_instanceof_guard_class(self):
+## ops = """
+## [i0, p0]
+## guard_class(p0, ConstClass(node_vtable)) []
+## i1 = instanceof(p0, descr=nodesize)
+## jump(i1, p0)
+## """
+## expected = """
+## [i0, p0]
+## guard_class(p0, ConstClass(node_vtable)) []
+## jump(1, p0)
+## """
+## self.optimize_loop(ops, expected)