[pypy-commit] pypy vecopt: rewritten the guard strengthening. it is now independent from vecopt (still contained in the same file though).

plan_rich noreply at buildbot.pypy.org
Thu May 21 18:26:40 CEST 2015


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt
Changeset: r77454:1f73ac83382c
Date: 2015-05-21 18:26 +0200
http://bitbucket.org/pypy/pypy/changeset/1f73ac83382c/

Log:	rewritten the guard strengthening. it is now independent from vecopt
	(still contained in the same file though). the previous version was
	not correct and could only rewrite int_add. now if a guard implies a
	previous guard, the earlier guard is replaced directly

diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py
--- a/rpython/jit/metainterp/optimizeopt/dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/dependency.py
@@ -2,7 +2,7 @@
 
 from rpython.jit.metainterp import compile
 from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from rpython.jit.metainterp.resoperation import (rop, GuardResOp)
+from rpython.jit.metainterp.resoperation import (rop, GuardResOp, ResOperation)
 from rpython.jit.metainterp.resume import Snapshot
 from rpython.jit.codewriter.effectinfo import EffectInfo
 from rpython.jit.metainterp.history import BoxPtr, ConstPtr, ConstInt, BoxInt, Box, Const, BoxFloat
@@ -83,6 +83,9 @@
         self.emitted = False
         self.schedule_position = -1
         self.priority = 0
+        # save the operation that produces the result for the first argument
+        # only for guard_true/guard_false
+        self.guard_bool_bool_node = None
 
     def getoperation(self):
         return self.op
@@ -531,8 +534,7 @@
                 self.build_non_pure_dependencies(node, tracker)
         # pass 2 correct guard dependencies
         for guard_node in self.guards:
-            op = guard_node.getoperation()
-            self.build_guard_dependencies(guard_node, op.getopnum(), tracker)
+            self.build_guard_dependencies(guard_node, tracker)
         # pass 3 find schedulable nodes
         jump_node = self.nodes[jump_pos]
         label_node = self.nodes[label_pos]
@@ -559,9 +561,15 @@
         if guard_opnum in (rop.GUARD_TRUE, rop.GUARD_FALSE):
             for dep in guard_node.depends():
                 op = dep.to.getoperation()
-                for arg in op.getarglist():
-                    if isinstance(arg, Box):
-                        self.guard_exit_dependence(guard_node, arg, tracker)
+                if op.returns_bool_result() and op.result == guard_op.getarg(0):
+                    guard_node.guard_bool_bool_node = dep.to
+                    for arg in op.getarglist():
+                        if isinstance(arg, Box):
+                            self.guard_exit_dependence(guard_node, arg, tracker)
+                    break
+            else:
+                raise RuntimeError("guard_true/false has no operation that " \
+                                   "returns the bool for the arg 0")
         elif guard_op.is_foldable_guard():
             # these guards carry their protected variables directly as a parameter
             for arg in guard_node.getoperation().getarglist():
@@ -598,12 +606,12 @@
             if guard_node.is_before(dep.to) and dep.because_of(var):
                 guard_node.edge_to(dep.to, var, label='guard_exit('+str(var)+')')
 
-    def build_guard_dependencies(self, guard_node, guard_opnum, tracker):
-        if guard_opnum >= rop.GUARD_NOT_INVALIDATED:
+    def build_guard_dependencies(self, guard_node, tracker):
+        guard_op = guard_node.op
+        if guard_op.getopnum() >= rop.GUARD_NOT_INVALIDATED:
             # ignore invalidated & future condition guard & early exit
             return
         # true dependencies
-        guard_op = guard_node.op
         for arg in guard_op.getarglist():
             tracker.depends_on_arg(arg, guard_node)
         # dependencies to uses of arguments it protects
@@ -970,6 +978,33 @@
         othercoeff = other.coefficient_mul // other.coefficient_div
         return mycoeff + self.constant - (othercoeff + other.constant)
 
+    def emit_operations(self, opt):
+        box = self.var
+        if self.coefficient_mul != 1:
+            box_result = box.clonebox()
+            opt.emit_operation(ResOperation(rop.INT_MUL, [box, ConstInt(self.coefficient_mul)], box_result))
+            box = box_result
+        if self.coefficient_div != 1:
+            box_result = box.clonebox()
+            opt.emit_operation(ResOperation(rop.INT_FLOORDIV, [box, ConstInt(self.coefficient_div)], box_result))
+            box = box_result
+        if self.constant != 0:
+            box_result = box.clonebox()
+            opt.emit_operation(ResOperation(rop.INT_ADD, [box, ConstInt(self.constant)], box_result))
+            box = box_result
+        return box
+
+    def compare(self, other):
+        assert isinstance(other, IndexVar)
+        v1 = (self.coefficient_mul // self.coefficient_div) + self.constant
+        v2 = (other.coefficient_mul // other.coefficient_div) + other.constant
+        if v1 == v2:
+            return 0
+        elif v1 < v2:
+            return -1
+        else:
+            return 1
+
     def __repr__(self):
         if self.is_identity():
             return 'IndexVar(%s+%s)' % (self.var, repr(self.next_nonconst))
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vectorize.py b/rpython/jit/metainterp/optimizeopt/test/test_vectorize.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_vectorize.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_vectorize.py
@@ -12,7 +12,7 @@
 from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph
 from rpython.jit.metainterp.optimizeopt.unroll import Inliner
 from rpython.jit.metainterp.optimizeopt.vectorize import (VectorizingOptimizer, MemoryRef,
-        isomorphic, Pair, NotAVectorizeableLoop, NotAVectorizeableLoop)
+        isomorphic, Pair, NotAVectorizeableLoop, NotAVectorizeableLoop, GuardStrengthenOpt)
 from rpython.jit.metainterp.optimize import InvalidLoop
 from rpython.jit.metainterp.history import ConstInt, BoxInt, get_const_ptr_for_string
 from rpython.jit.metainterp import executor, compile, resume
@@ -102,7 +102,8 @@
         opt.extend_packset()
         opt.combine_packset()
         opt.schedule()
-        opt.collapse_index_guards()
+        gso = GuardStrengthenOpt(opt.dependency_graph.index_vars)
+        gso.propagate_all_forward(opt.loop)
         return opt
 
     def assert_unroll_loop_equals(self, loop, expected_loop, \
@@ -879,30 +880,6 @@
         vopt = self.schedule(loop,1)
         self.assert_equal(loop, self.parse_loop(vops))
 
-    @pytest.mark.parametrize('unroll', [1])
-    def test_vectorize_index_variable_combination(self, unroll):
-        ops = """
-        [p0,i0]
-        guard_early_exit() []
-        i1 = raw_load(p0, i0, descr=floatarraydescr)
-        i2 = int_add(i0,8)
-        jump(p0,i2)
-        """
-        vops = """
-        [p0,i0]
-        guard_early_exit() []
-        """ + '\n        '.join(["i{x} = int_add(i0,{i})".format(i=8*(i+1),x=i+100) for i in range(unroll) ]) + \
-        """
-        i1 = int_add(i0, {count})
-        v1 = vec_raw_load(p0, i0, {elems}, descr=floatarraydescr)
-        jump(p0,i1)
-        """.format(count=(unroll+1)*8,elems=unroll+1)
-        print vops
-        loop = self.parse_loop(ops)
-        vopt = self.vectorize(loop,unroll)
-        self.assert_equal(loop, self.parse_loop(vops))
-
-
     def test_vschedule_trace_1(self):
         ops = """
         [i0, i1, i2, i3, i4]
@@ -948,18 +925,22 @@
         jump(p0,i2)
         """
         dead_code =  '\n        '.join([
-          "i{t} = int_add(i0,{i})\n        i{s} = int_lt(i{t}, 102)".format(
-              i=i+1, t=i+4, s=i+20)
-          for i in range(0,15)])
+          "i{t1} = int_add(i{t},1)\n        i{s} = int_lt(i{t1}, 102)".format(
+              i=i+1, t1=i+201, t=i+200, s=i+20)
+          for i in range(0,14)])
         opt="""
         [p0,i0]
         guard_early_exit() [p0,i0]
-        {dead_code}
+        i200 = int_add(i0, 1)
+        i400 = int_lt(i200, 102)
         i2 = int_add(i0, 16)
         i3 = int_lt(i2, 102)
         guard_true(i3) [p0,i0]
+        {dead_code}
+        i500 = same_as(i2)
+        i300 = int_lt(i500, 102)
         i1 = vec_getarrayitem_raw(p0, i0, 16, descr=chararraydescr)
-        jump(p0,i2)
+        jump(p0,i500)
         """.format(dead_code=dead_code)
         vopt = self.vectorize(self.parse_loop(ops),15)
         self.assert_equal(vopt.loop, self.parse_loop(opt))
@@ -1001,10 +982,12 @@
         i2 = int_add(i0, 2)
         i3 = int_lt(i2, 10)
         guard_true(i3) [p0,i0]
+        i4 = same_as(i2)
+        i5 = int_lt(i4, 10)
         v1 = vec_getarrayitem_raw(p0, i0, 2, descr=floatarraydescr)
         v3 = vec_int_expand(42)
         v2 = vec_int_mul(v1, v3, 2)
-        jump(p0,i2)
+        jump(p0,i4)
         """
         vopt = self.vectorize(self.parse_loop(ops),1)
         self.assert_equal(vopt.loop, self.parse_loop(opt))
@@ -1028,10 +1011,12 @@
         i2 = int_add(i0, 2)
         i3 = int_lt(i2, 10)
         guard_true(i3) [p0,i0]
+        i4 = same_as(i2)
+        i5 = int_lt(i4, 10)
         v1 = vec_getarrayitem_raw(p0, i0, 2, descr=floatarraydescr)
         v3 = vec_float_expand(f3)
         v2 = vec_int_mul(v1, v3, 2)
-        jump(p0,i2,f3)
+        jump(p0,i4,f3)
         """
         vopt = self.vectorize(self.parse_loop(ops),1)
         self.assert_equal(vopt.loop, self.parse_loop(opt))
@@ -1062,10 +1047,11 @@
         i48 = int_add(i41, 8) 
         i51 = int_add(i37, 8) 
         i52 = int_ge(i50, i18) 
-        i55 = int_add(i44, 16) 
-        i54 = int_add(i41, 16) 
-        i56 = int_add(i37, 16) 
-        i53 = int_add(i28, 2) 
+        guard_false(i52) [p38, p12, p9, p14, p39, i37, i44, f35, i40, p42, i43, f34, i28, p36, i41]
+        i55 = int_add(i46, 8) 
+        i54 = int_add(i48, 8) 
+        i56 = int_add(i51, 8) 
+        i53 = int_add(i50, 1)
         i57 = int_ge(i53, i18) 
         guard_false(i57) [p38, p12, p9, p14, p39, i37, i44, f35, i40, p42, i43, f34, i28, p36, i41]
         v61 = vec_raw_load(i21, i44, 2, descr=floatarraydescr) 
@@ -1106,7 +1092,7 @@
         try:
             vopt = self.vectorize(self.parse_loop(ops))
             self.debug_print_operations(vopt.loop)
-            # TODO verify
+            py.test.fail("this loop should not be vectorized")
         except NotAVectorizeableLoop:
             pass
 
@@ -1117,7 +1103,7 @@
         f1 = getarrayitem_raw(p0, i1, descr=floatarraydescr)
         i2 = cast_float_to_singlefloat(f1)
         setarrayitem_raw(p1, i1, i2, descr=singlefloatarraydescr)
-        i3 = int_add(i1, 1)
+        i3 = int_sub(i1, 1)
         i4 = int_ge(i3, 36)
         guard_false(i4) []
         jump(p0, p1, i3)
@@ -1125,15 +1111,17 @@
         opt = """
         [p0, p1, i1]
         guard_early_exit() []
-        i3 = int_add(i1, 1)
+        i3 = int_sub(i1, 1)
         i4 = int_ge(i3, 36)
-        i5 = int_add(i1, 2)
+        i50 = int_add(i1, -4)
+        i51 = int_ge(i50, 36)
+        guard_false(i51) []
+        i5 = int_sub(i3, 1)
         i8 = int_ge(i5, 36)
-        i6 = int_add(i1, 3)
+        i6 = int_sub(i5, 1)
         i11 = int_ge(i6, 36)
-        i7 = int_add(i1, 4)
+        i7 = same_as(i50)
         i14 = int_ge(i7, 36)
-        guard_false(i14) []
         v17 = vec_getarrayitem_raw(p0, i1, 2, descr=floatarraydescr)
         v18 = vec_getarrayitem_raw(p0, i5, 2, descr=floatarraydescr)
         v19 = vec_cast_float_to_singlefloat(v17, 2)
@@ -1168,16 +1156,18 @@
         i5 = int_add(i4, 4)
         i1 = int_add(i0, 4)
         i186 = int_lt(i5, 100)
-        i189 = int_add(i0, 8)
-        i187 = int_add(i4, 8)
-        i198 = int_add(i0, 12)
+        i500 = int_add(i4, 16)
+        i501 = int_lt(i500, 100)
+        guard_false(i501) []
+        i189 = int_add(i1, 4)
+        i187 = int_add(i5, 4)
+        i198 = int_add(i189, 4)
         i188 = int_lt(i187, 100)
-        i207 = int_add(i0, 16)
-        i196 = int_add(i4, 12)
+        i207 = int_add(i198, 4)
+        i196 = int_add(i187, 4)
         i197 = int_lt(i196, 100)
-        i205 = int_add(i4, 16)
+        i205 = same_as(i500)
         i206 = int_lt(i205, 100)
-        guard_false(i206) []
         v228 = vec_raw_load(p0, i0, 4, descr=singlefloatarraydescr)
         v229 = vec_cast_singlefloat_to_float(v228, 2)
         v230 = vec_int_unpack(v228, 2, 2)
diff --git a/rpython/jit/metainterp/optimizeopt/vectorize.py b/rpython/jit/metainterp/optimizeopt/vectorize.py
--- a/rpython/jit/metainterp/optimizeopt/vectorize.py
+++ b/rpython/jit/metainterp/optimizeopt/vectorize.py
@@ -9,7 +9,7 @@
 from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization
 from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, 
-        MemoryRef, Scheduler, SchedulerData, Node)
+        MemoryRef, Scheduler, SchedulerData, Node, IndexVar)
 from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp)
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rlib.debug import debug_print, debug_start, debug_stop
@@ -111,7 +111,8 @@
         self.combine_packset()
         self.schedule()
 
-        self.collapse_index_guards()
+        gso = GuardStrengthenOpt(self.dependency_graph.index_vars)
+        gso.propagate_all_forward(self.loop)
 
     def emit_operation(self, op):
         if op.getopnum() == rop.DEBUG_MERGE_POINT:
@@ -399,6 +400,8 @@
 
     def unpack_from_vector(self, op, sched_data):
         args = op.getarglist()
+        if op.is_guard():
+            py.test.set_trace()
         for i, arg in enumerate(op.getarglist()):
             if isinstance(arg, Box):
                 self._unpack_from_vector(args, i, arg, sched_data)
@@ -427,9 +430,7 @@
     def analyse_index_calculations(self):
         if len(self.loop.operations) <= 1 or self.early_exit_idx == -1:
             return
-
         self.dependency_graph = graph = DependencyGraph(self.loop)
-
         label_node = graph.getnode(0)
         ee_guard_node = graph.getnode(self.early_exit_idx)
         guards = graph.guards
@@ -437,7 +438,6 @@
             if guard_node is ee_guard_node:
                 continue
             modify_later = []
-            valid_trans = True
             last_prev_node = None
             for path in guard_node.iterate_paths(ee_guard_node, True):
                 prev_node = path.second()
@@ -453,7 +453,7 @@
                         #   |
                         #  (g)
                         # this graph yields 2 paths from (g), thus (a) is
-                        # remembered and skipped
+                        # remembered and skipped the second time visited
                         continue
                     modify_later.append((prev_node, guard_node))
                 else:
@@ -461,10 +461,13 @@
                         path.set_schedule_priority(10)
                         modify_later.append((path.last_but_one(), None))
                     else:
-                        valid_trans = False
+                        # transformation is invalid.
+                        # exit and do not enter else branch!
                         break
                 last_prev_node = prev_node
-            if valid_trans:
+            else:
+                # transformation is valid, modify the graph and execute
+                # this guard earlier
                 for a,b in modify_later:
                     if b is not None:
                         a.remove_edge_to(b)
@@ -478,53 +481,187 @@
                 guard_node.edge_to(ee_guard_node, label='pullup-last-guard')
                 guard_node.relax_guard_to(ee_guard_node)
 
-    def collapse_index_guards(self):
+class Guard(object):
+    """ An object wrapper around a guard. Helps to determine
+        if one guard implies another
+    """
+    def __init__(self, op, cmp_op, lhs, rhs):
+        self.op = op
+        self.cmp_op = cmp_op
+        self.lhs = lhs
+        self.rhs = rhs
+        self.emitted = False
+        self.stronger = False
+
+    def implies(self, guard, opt):
+        print self.cmp_op, "=>", guard.cmp_op, "?"
+        my_key = opt._get_key(self.cmp_op)
+        ot_key = opt._get_key(guard.cmp_op)
+
+        if my_key[1] == ot_key[1]:
+            # same operation
+            lc = self.compare(self.lhs, guard.lhs)
+            rc = self.compare(self.rhs, guard.rhs)
+            print "compare", self.lhs, guard.lhs, lc
+            print "compare", self.rhs, guard.rhs, rc
+            opnum = my_key[1]
+            # x < y  = -1,-2,...
+            # x == y = 0
+            # x > y  = 1,2,...
+            if opnum == rop.INT_LT:
+                return (lc > 0 and rc >= 0) or (lc == 0 and rc >= 0)
+            if opnum == rop.INT_LE:
+                return (lc >= 0 and rc >= 0) or (lc == 0 and rc >= 0)
+            if opnum == rop.INT_GT:
+                return (lc < 0 and rc >= 0) or (lc == 0 and rc > 0)
+            if opnum == rop.INT_GE:
+                return (lc <= 0 and rc >= 0) or (lc == 0 and rc >= 0)
+        return False
+
+    def compare(self, key1, key2):
+        if isinstance(key1, Box):
+            assert isinstance(key2, Box)
+            assert key1 is key2 # key of hash enforces this
+            return 0
+        #
+        if isinstance(key1, ConstInt):
+            assert isinstance(key2, ConstInt)
+            v1 = key1.value
+            v2 = key2.value
+            if v1 == v2:
+                return 0
+            elif v1 < v2:
+                return -1
+            else:
+                return 1
+        #
+        if isinstance(key1, IndexVar):
+            assert isinstance(key2, IndexVar)
+            return key1.compare(key2)
+        #
+        raise RuntimeError("cannot compare: " + str(key1) + " <=> " + str(key2))
+
+    def emit_varops(self, opt, var):
+        if isinstance(var, IndexVar):
+            box = var.emit_operations(opt)
+            opt._same_as[var] = box
+            return box
+        else:
+            return var
+
+    def emit_operations(self, opt):
+        lhs, opnum, rhs = opt._get_key(self.cmp_op)
+        # create trace instructions for the index
+        box_lhs = self.emit_varops(opt, self.lhs)
+        box_rhs = self.emit_varops(opt, self.rhs)
+        box_result = self.cmp_op.result.clonebox()
+        opt.emit_operation(ResOperation(opnum, [box_lhs, box_rhs], box_result))
+        # guard
+        guard = self.op.clone()
+        guard.setarg(0, box_result)
+        opt.emit_operation(guard)
+
+class GuardStrengthenOpt(object):
+    def __init__(self, index_vars):
+        self.index_vars = index_vars
+        self._newoperations = []
+        self._same_as = {}
+
+    def find_compare_guard_bool(self, boolarg, operations, index):
+        i = index - 1
+        # most likely hit in the first iteration
+        while i > 0:
+            op = operations[i]
+            if op.result and op.result == boolarg:
+                return op
+            i -= 1
+
+        raise RuntimeError("guard_true/false first arg not defined")
+
+    def _get_key(self, cmp_op):
+        if cmp_op and rop.INT_LT <= cmp_op.getopnum() <= rop.INT_GE:
+            lhs_arg = cmp_op.getarg(0)
+            rhs_arg = cmp_op.getarg(1)
+            lhs_index_var = self.index_vars.get(lhs_arg, None)
+            rhs_index_var = self.index_vars.get(rhs_arg, None)
+
+            cmp_opnum = cmp_op.getopnum()
+            # get the key, this identifies the guarded operation
+            if lhs_index_var and rhs_index_var:
+                key = (lhs_index_var.getvariable(), cmp_opnum, rhs_index_var.getvariable())
+            elif lhs_index_var:
+                key = (lhs_index_var.getvariable(), cmp_opnum, rhs_arg)
+            elif rhs_index_var:
+                key = (lhs_arg, cmp_opnum, rhs_index_var)
+            else:
+                key = (lhs_arg, cmp_opnum, rhs_arg)
+            return key
+        return None
+
+
+    def get_key(self, guard_bool, operations, i):
+        cmp_op = self.find_compare_guard_bool(guard_bool.getarg(0), operations, i)
+        return self._get_key(cmp_op)
+
+    def propagate_all_forward(self, loop):
+        """ strengthens the guards that protect an integral value """
         strongest_guards = {}
-        strongest_guards_var = {}
-        index_vars = self.dependency_graph.index_vars
-        comparison_vars = self.dependency_graph.comparison_vars
-        operations = self.loop.operations
-        var_for_guard = {}
-        for i in range(len(operations)-1, -1, -1):
+        # index_vars = self.dependency_graph.index_vars
+        # comparison_vars = self.dependency_graph.comparison_vars
+        # the guards are ordered. guards[i] is before guards[j] iff i < j
+        operations = loop.operations
+        last_guard = None
+        for i,op in enumerate(operations):
             op = operations[i]
-            if op.is_guard():
-                for arg in op.getarglist():
-                    var_for_guard[arg] = True
-                    try:
-                        comparison = comparison_vars[arg]
-                        for index_var in list(comparison.getindex_vars()):
-                            if not index_var:
-                                continue
-                            var = index_var.getvariable()
-                            strongest_known = strongest_guards_var.get(var, None)
-                            if not strongest_known:
-                                strongest_guards_var[var] = index_var
-                                continue
-                            if index_var.less(strongest_known):
-                                strongest_guards_var[var] = strongest_known
-                                strongest_guards[op] = strongest_known
-                    except KeyError:
-                        pass
-
+            if op.is_guard() and op.getopnum() in (rop.GUARD_TRUE, rop.GUARD_FALSE):
+                cmp_op = self.find_compare_guard_bool(op.getarg(0), operations, i)
+                key = self._get_key(cmp_op)
+                if key:
+                    lhs_arg = cmp_op.getarg(0)
+                    lhs = self.index_vars.get(lhs_arg, lhs_arg)
+                    rhs_arg = cmp_op.getarg(1)
+                    rhs = self.index_vars.get(rhs_arg, rhs_arg)
+                    strongest = strongest_guards.get(key, None)
+                    if not strongest:
+                        strongest_guards[key] = Guard(op, cmp_op, lhs, rhs)
+                    else:
+                        guard = Guard(op, cmp_op, lhs, rhs)
+                        if guard.implies(strongest, self):
+                            guard.stronger = True
+                            strongest_guards[key] = guard
+        #
         last_op_idx = len(operations)-1
-        for op in operations:
-            if op.is_guard():
-                stronger_guard = strongest_guards.get(op, None)
-                if stronger_guard:
-                    # there is a stronger guard
+        for i,op in enumerate(operations):
+            op = operations[i]
+            if op.is_guard() and op.getopnum() in (rop.GUARD_TRUE, rop.GUARD_FALSE):
+                key = self.get_key(op, operations, i)
+                if key:
+                    strongest = strongest_guards.get(key, None)
+                    if not strongest or not strongest.stronger:
+                        # If the key is not None and there _must_ be a strongest
+                        # guard. If strongest is None, this operation implies the
+                        # strongest guard that has been already been emitted.
+                        self.emit_operation(op)
+                        continue
+                    elif strongest.emitted:
+                        continue
+                    strongest.emit_operations(self)
+                    strongest.emitted = True
                     continue
-                else:
-                    self.emit_operation(op)
+            if op.result:
+                # emit a same_as op if a box uses the same index variable
+                index_var = self.index_vars.get(op.result, None)
+                box = self._same_as.get(index_var, None)
+                if box:
+                    self.emit_operation(ResOperation(rop.SAME_AS, [box], op.result))
                     continue
-            if op.is_always_pure() and op.result:
-                try:
-                    var_index = index_vars[op.result]
-                    var_index.adapt_operation(op)
-                except KeyError:
-                    pass
             self.emit_operation(op)
 
-        self.loop.operations = self._newoperations[:]
+        loop.operations = self._newoperations[:]
+
+    def emit_operation(self, op):
+        self._newoperations.append(op)
+
 
 def must_unpack_result_to_exec(op, target_op):
     # TODO either move to resop or util


More information about the pypy-commit mailing list