[pypy-commit] pypy vecopt2: starting to modify the dependency construction to track all integral modifications

plan_rich noreply at buildbot.pypy.org
Tue May 5 09:45:57 CEST 2015


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt2
Changeset: r77106:24298bf280c1
Date: 2015-04-08 16:36 +0200
http://bitbucket.org/pypy/pypy/changeset/24298bf280c1/

Log:	starting to modify the dependency construction to track all integral
	modifications

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
@@ -53,6 +53,10 @@
         else:
             self.defs[arg] = [(index,argcell)]
 
+    def redefintions(self, arg):
+        for _def in self.defs[arg]:
+            yield _def[0]
+
     def definition_index(self, arg, index = -1, argcell=None):
         def_chain = self.defs[arg]
         if len(def_chain) == 1:
@@ -103,6 +107,8 @@
         self.integral_mod = IntegralMod()
         self.schedulable_nodes = [0] # label is always scheduleable
         self.build_dependencies()
+        self.index_vars = {}
+        self.guards = []
 
     def build_dependencies(self):
         """ This is basically building the definition-use chain and saving this
@@ -114,7 +120,7 @@
         """
         tracker = DefTracker(self.memory_refs)
         #
-        guards = []
+        intformod = IntegralForwardModification(self.index_vars)
         # pass 1
         for i,op in enumerate(self.operations):
             # the label operation defines all operations at the
@@ -122,6 +128,9 @@
             if op.getopnum() == rop.LABEL:
                 for arg in op.getarglist():
                     tracker.define(arg, 0)
+                    if isinstance(arg, BoxInt):
+                        assert arg not in self.index_vars
+                        self.index_vars[arg] = IndexVar(arg)
                 continue # prevent adding edge to the label itself
             # definition of a new variable
             if op.result is not None:
@@ -133,21 +142,20 @@
                 for arg in op.getarglist():
                     self._def_use(arg, i, tracker)
             elif op.is_guard():
-                guards.append(i)
+                self.guards.append(i)
             else:
                 self._build_non_pure_dependencies(op, i, tracker)
-        #
+            intformod.inspect_operation(op, i)
         # pass 2 correct guard dependencies
-        for guard_idx in guards:
+        for guard_idx in self.guards:
             self._build_guard_dependencies(guard_idx, op.getopnum(), tracker)
         # pass 3 find schedulable nodes
         jump_pos = len(self.operations)-1
         for i,op in enumerate(self.operations):
             if len(self.adjacent_list[i]) == 0:
                 self.schedulable_nodes.append(i)
-            # every leaf instruction points to the jump_op. in theory
-            # every instruction points to jump_op, this is an optimization
-            # to prevent the scheduling of ops before the jump operation
+            # every leaf instruction points to the jump_op. in theory every instruction
+            # points to jump_op. this forces the jump/finish op to be the last operation
             if i != jump_pos:
                 for dep in self.adjacent_list[i]:
                     if dep.idx_to > i:
@@ -170,7 +178,6 @@
         for arg in guard_op.getarglist():
             self._def_use(arg, guard_idx, tracker)
 
-        print "guard[", guard_idx, "]", guard_op
         variables = []
         for dep in self.depends(guard_idx):
             idx = dep.idx_from
@@ -178,18 +185,16 @@
             for arg in op.getarglist():
                 if isinstance(arg, Box):
                     variables.append(arg)
-                    print " + in spe", arg
             if op.result:
                 variables.append(op.result)
-                print " + in spe res", op.result
         #
         for var in variables:
             try:
                 def_idx = tracker.definition_index(var)
                 for dep in self.provides(def_idx):
                     if var in dep.args and dep.idx_to > guard_idx:
-                        print "checking", var, "def at", def_idx, " -> ", dep
-                        print " ==> yes"
+                        #print "checking", var, "def at", def_idx, " -> ", dep
+                        #print " ==> yes"
                         self._put_edge(guard_idx, dep.idx_to, var)
             except KeyError:
                 pass
@@ -198,8 +203,9 @@
         if op.getfailargs():
             for arg in op.getfailargs():
                 try:
-                    def_idx = tracker.definition_index(arg)
-                    #self._put_edge(def_idx, guard_idx, arg)
+                    for def_idx in tracker.redefintions(arg):
+                        self._put_edge(def_idx, guard_idx, arg)
+                        #print "put arg", arg, ":", def_idx, guard_idx,"!!!"
                 except KeyError:
                     assert False
         #
@@ -300,6 +306,7 @@
         return args
 
     def _update_memory_ref(self, op, index, tracker):
+        # deprecated
         if index not in self.memory_refs:
             return
         memref = self.memory_refs[index]
@@ -327,9 +334,10 @@
         assert idx_from != idx_to
         dep = self.directly_depends(idx_from, idx_to)
         if not dep:
-            dep = Dependency(idx_from, idx_to, arg)
-            self.adjacent_list[idx_from].append(dep)
-            self.adjacent_list[idx_to].append(dep)
+            if self.independent(idx_from, idx_to):
+                dep = Dependency(idx_from, idx_to, arg)
+                self.adjacent_list[idx_from].append(dep)
+                self.adjacent_list[idx_to].append(dep)
         else:
             if arg not in dep.args:
                 dep.args.append(arg)
@@ -399,6 +407,7 @@
 
     def directly_depends(self, from_idx, to_idx):
         return self.instr_dependency(from_idx, to_idx)
+
     def instr_dependency(self, from_instr_idx, to_instr_idx):
         # XXX
         """ Does there exist a dependency from the instruction to another?
@@ -512,6 +521,83 @@
     def is_schedulable(self, idx):
         return self.graph.depends_count(idx) == 0
 
+class IntegralForwardModification(object):
+    """ Calculates integral modifications on an integer box. """
+    def __init__(self, index_vars):
+        self.index_vars = index_vars
+
+    def is_const_integral(self, box):
+        if isinstance(box, ConstInt):
+            return True
+        return False
+
+    additive_func_source = """
+    def operation_{name}(self, op, index):
+        box_r = op.result
+        if not box_r:
+            return
+        box_a0 = op.getarg(0)
+        box_a1 = op.getarg(1)
+        if self.is_const_integral(box_a0) and self.is_const_integral(box_a1):
+            idx_ref = IndexVar(box_r)
+            idx_ref.constant = box_a0.getint() {op} box_a1.getint())
+            self.index_vars[box_r] = idx_ref 
+        elif self.is_const_integral(box_a0):
+            idx_ref = self.index_vars[box_a0]
+            idx_ref = idx_ref.clone(box_r)
+            idx_ref.constant {op}= box_a0.getint()
+            self.index_vars[box_r] = idx_ref
+        elif self.is_const_integral(box_a1):
+            idx_ref = self.index_vars[box_a1]
+            idx_ref = idx_ref.clone(box_r)
+            idx_ref.constant {op}= box_a1.getint()
+            self.index_vars[box_r] = idx_ref
+    """
+    exec py.code.Source(additive_func_source.format(name='INT_ADD', 
+                                                    op='+')).compile()
+    exec py.code.Source(additive_func_source.format(name='INT_SUB', 
+                                                    op='-')).compile()
+    del additive_func_source
+
+    multiplicative_func_source = """
+    def operation_{name}(self, op):
+        box_r = op.result
+        if not box_r:
+            return
+        box_a0 = op.getarg(0)
+        box_a1 = op.getarg(1)
+        if self.is_const_integral(box_a0) and self.is_const_integral(box_a1):
+            idx_ref = IndexVar(box_r)
+            idx_ref.constant = box_a0.getint() {cop} box_a1.getint())
+            self.index_vars[box_r] = idx_ref 
+        elif self.is_const_integral(box_a0):
+            idx_ref = self.index_vars[box_a0]
+            idx_ref = idx_ref.clone(box_r)
+            self.coefficient_{tgt} *= box_a0.getint()
+            self.constant {cop}= box_a0.getint()
+            self.index_vars[box_r] = idx_ref
+        elif self.is_const_integral(box_a1):
+            idx_ref = self.index_vars[box_a1]
+            idx_ref = idx_ref.clone(box_r)
+            self.coefficient_{tgt} {op}= box_a1.getint()
+            self.constant {cop}= box_a1.getint()
+            self.index_vars[box_r] = idx_ref
+    """
+    exec py.code.Source(multiplicative_func_source.format(name='INT_MUL', 
+                                                 op='*', tgt='mul',
+                                                 cop='*')).compile()
+    exec py.code.Source(multiplicative_func_source.format(name='INT_FLOORDIV',
+                                                 op='*', tgt='div',
+                                                 cop='/')).compile()
+    exec py.code.Source(multiplicative_func_source.format(name='UINT_FLOORDIV',
+                                                 op='*', tgt='div',
+                                                 cop='/')).compile()
+    del multiplicative_func_source
+
+integral_dispatch_opt = make_dispatcher_method(IntegralForwardModification, 'operation_')
+IntegralForwardModification.inspect_operation = integral_dispatch_opt
+del integral_dispatch_opt
+
 class IntegralMod(object):
     """ Calculates integral modifications on an integer object.
     The operations must be provided in backwards direction and of one
@@ -532,11 +618,6 @@
     def _update_additive(self, i):
         return (i * self.coefficient_mul) / self.coefficient_div
 
-    def is_const_integral(self, box):
-        if isinstance(box, ConstInt):
-            return True
-        return False
-
     additive_func_source = """
     def operation_{name}(self, op):
         box_a0 = op.getarg(0)
@@ -592,6 +673,11 @@
                                                  cop='/')).compile()
     del multiplicative_func_source
 
+    def is_const_integral(self, box):
+        if isinstance(box, ConstInt):
+            return True
+        return False
+
     def update_memory_ref(self, memref):
         memref.constant = self.constant
         memref.coefficient_mul = self.coefficient_mul
@@ -605,6 +691,43 @@
 IntegralMod.inspect_operation = integral_dispatch_opt
 del integral_dispatch_opt
 
+class IndexVar(object):
+    def __init__(self, var):
+        self.var = var
+        self.coefficient_mul = 1
+        self.coefficient_div = 1
+        self.constant = 0
+
+    def __eq__(self, other):
+        if self.same_variable(other):
+            return self.diff(other) == 0
+        return False
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def clone(self, box):
+        c = IndexVar(box)
+        c.coefficient_mul = self.coefficient_mul
+        c.coefficient_div = self.coefficient_div
+        c.constant = self.constant
+        return c
+
+    def same_variable(self, other):
+        assert isinstance(other, IndexVar)
+        return other.var == self.var
+
+    def diff(self, other):
+        """ calculates the difference as a second parameter """
+        assert isinstance(other, IndexVar)
+        mycoeff = self.coefficient_mul // self.coefficient_div
+        othercoeff = other.coefficient_mul // other.coefficient_div
+        return mycoeff + self.constant - (othercoeff + other.constant)
+
+    def __repr__(self):
+        return 'IndexVar(%s*(%s/%s)+%s)' % (self.var, self.coefficient_mul,
+                                            self.coefficient_div, self.constant)
+
 class MemoryRef(object):
     """ a memory reference to an array object. IntegralMod is able
     to propagate changes to this object if applied in backwards direction.
@@ -616,33 +739,37 @@
 
     will result in the linear combination i0 * (2/1) + 2
     """
-    def __init__(self, array, origin, descr):
+    def __init__(self, array, origin, descr, index_ref, byte_index=False):
         assert descr is not None
         self.array = array
-        self.origin = origin
         self.descr = descr
-        self.coefficient_mul = 1
-        self.coefficient_div = 1
-        self.constant = 0
+        self.index_ref = index_ref
+        self.byte_index = byte_index
 
     def is_adjacent_to(self, other):
         """ this is a symmetric relation """
-        match, off = self.calc_difference(other)
         stride = self.stride()
-        if match and stride != 0:
-            return abs(off) - stride == 0
+        if self.match(other):
+            return abs(self.index_ref.diff(other.index_ref)) - stride == 0
+        return False
+
+    def match(self, other):
+        assert isinstance(other, MemoryRef)
+        if self.array == other.array and self.descr == other.descr:
+            return self.index_ref.same_variable(other.index_ref):
         return False
 
     def stride(self):
         """ the stride in bytes """
+        if not self.byte_index:
+            return 1
         return self.descr.get_item_size_in_bytes()
 
     def is_adjacent_after(self, other):
         """ the asymetric relation to is_adjacent_to """
-        match, off = self.calc_difference(other)
         stride = self.stride()
-        if match and stride != 0:
-            return off == stride # must be equal to the positive stride
+        if self.match(other):
+            return self.index_ref.diff(other.index_ref) == stride
         return False
 
     def indices_can_alias(self, other):
@@ -650,35 +777,21 @@
         self.origin != other.origin, or their
         linear combination point to the same element.
         """
-        match, off = self.calc_difference(other)
-        if match:
-            return abs(off) < self.stride()
+        if self.index_ref.same_variable(other.index_ref):
+            return True
+        stride = self.stride()
+        if self.match(other):
+            return abs(self.index_ref.diff(other.index_ref)) < stride
         return False
 
     def __eq__(self, other):
-        match, off = self.calc_difference(other)
-        if match:
-            return off == 0
+        if self.match(other):
+            return self.index_ref.diff(other.index_ref) == 0
         return False
 
     def __ne__(self, other):
         return not self.__eq__(other)
 
-    def accesses_same_object(self, other):
-        assert isinstance(other, MemoryRef)
-        return self.array == other.array
-
-    def calc_difference(self, other):
-        """ calculates the difference in bytes as second return value """
-        assert isinstance(other, MemoryRef)
-        if self.array == other.array \
-            and self.origin == other.origin:
-            mycoeff = self.coefficient_mul // self.coefficient_div
-            othercoeff = other.coefficient_mul // other.coefficient_div
-            diff = other.constant - self.constant
-            return mycoeff == othercoeff, diff
-        return False, 0
-
     def __repr__(self):
-        return 'MemoryRef(%s*(%s/%s)+%s)' % (self.origin, self.coefficient_mul,
+        return 'MemRef(%s,%s*(%s/%s)+%s)' % (self.array, self.origin, self.coefficient_mul,
                                             self.coefficient_div, self.constant)
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
@@ -766,15 +766,25 @@
         self.assert_packset_empty(vopt.packset, len(loop.operations),
                                   [(5,11), (4,10), (6,12)])
 
-    @pytest.mark.parametrize("descr,stride",
-            [('char',1),('float',8),('int',8),('singlefloat',4)])
-    def test_packset_combine_simple(self,descr,stride):
+    @pytest.mark.parametrize("descr", ['char','float','int','singlefloat'])
+    def test_packset_combine_simple(self,descr):
         ops = """
         [p0,i0]
         i3 = getarrayitem_gc(p0, i0, descr={descr}arraydescr)
-        i1 = int_add(i0,{stride})
+        i1 = int_add(i0,1)
         jump(p0,i1)
-        """.format(descr=descr,stride=stride)
+        """.format(descr=descr)
+        loop = self.parse_loop(ops)
+        vopt = self.combine_packset(loop,3)
+        assert len(vopt.vec_info.memory_refs) == 4
+        assert len(vopt.packset.packs) == 1
+        self.assert_pack(vopt.packset.packs[0], (1,3,5,7))
+        ops = """
+        [p0,i0]
+        i3 = getarrayitem_raw(p0, i0, descr={descr}arraydescr)
+        i1 = int_add(i0,1)
+        jump(p0,i1)
+        """.format(descr=descr)
         loop = self.parse_loop(ops)
         vopt = self.combine_packset(loop,3)
         assert len(vopt.vec_info.memory_refs) == 4
@@ -786,15 +796,18 @@
     def test_packset_combine_2_loads_in_trace(self, descr, stride):
         ops = """
         [p0,i0]
-        i3 = getarrayitem_gc(p0, i0, descr={type}arraydescr)
+        i3 = raw_load(p0, i0, descr={type}arraydescr)
         i1 = int_add(i0,{stride})
-        i4 = getarrayitem_gc(p0, i1, descr={type}arraydescr)
+        i4 = raw_load(p0, i1, descr={type}arraydescr)
         i2 = int_add(i1,{stride})
         jump(p0,i2)
         """.format(type=descr,stride=stride)
         loop = self.parse_loop(ops)
         vopt = self.combine_packset(loop,3)
         assert len(vopt.vec_info.memory_refs) == 8
+        print "---"
+        for p in vopt.packset.packs:
+            print p
         assert len(vopt.packset.packs) == 1
         self.assert_pack(vopt.packset.packs[0], (1,3,5,7,9,11,13,15))
 
@@ -856,10 +869,10 @@
         i1 = int_add(i0, {stride})
         i10 = int_le(i1, 128)
         guard_true(i10) []
-        i2 = getarrayitem_gc(p0, i0, descr={descr}arraydescr)
-        i3 = getarrayitem_gc(p1, i0, descr={descr}arraydescr)
+        i2 = raw_load(p0, i0, descr={descr}arraydescr)
+        i3 = raw_load(p1, i0, descr={descr}arraydescr)
         i4 = {op}(i2,i3)
-        setarrayitem_gc(p2, i0, i4, descr={descr}arraydescr)
+        raw_store(p2, i0, i4, descr={descr}arraydescr)
         jump(p0,p1,p2,i1)
         """.format(op=op,descr=descr,stride=stride)
         loop = self.parse_loop(ops)
@@ -896,7 +909,7 @@
         setarrayitem_gc(p2, i0, i4, descr={descr}arraydescr) # 6, 13, 20, 27
         i1 = int_add(i0, {stride}) # 7, 14, 21, 28
         jump(p0,p1,p2,i1) # 29
-        """.format(op=op,descr=descr,stride=stride)
+        """.format(op=op,descr=descr,stride=1) # stride getarray is always 1
         vops = """
         [p0,p1,p2,i0]
         i10 = int_le(i0, 128)
@@ -910,7 +923,7 @@
         v3 = {op}(v1,v2)
         vec_raw_store(p2, i0, v3, 2, descr={descr}arraydescr)
         jump(p0,p1,p2,i12)
-        """.format(op='vec_'+op,descr=descr,stride=stride)
+        """.format(op='vec_'+op,descr=descr,stride=1)
         loop = self.parse_loop(ops)
         vopt = self.schedule(loop,1)
         self.debug_print_operations(vopt.loop)
@@ -959,19 +972,20 @@
         print "_--" * 10
         self.debug_print_operations(vopt.loop)
 
-    def test_vectorize_raw_load_add_index_item_byte_size(self):
+    def test_123(self):
         ops = """
-        [i0, i1, i2, i3, i4, i5, i6, i7]
-        i8 = raw_load(i3, i0, descr=intarraydescr)
-        i9 = raw_load(i4, i0, descr=intarraydescr)
-        i10 = int_add(i8, i9)
-        raw_store(i5, i0, i10, descr=intarraydescr)
-        i12 = int_add(i0, 8)
-        i14 = int_mul(i7, 8)
-        i15 = int_lt(i12, i14)
-        guard_true(i15) [i7, i10, i5, i4, i3, i9, i8, i12]
-        guard_future_condition() []
-        jump(i12, i8, i9, i3, i4, i5, i10, i7)
+        [i0, i1, i2, i3, i4]
+        debug_merge_point(0, 0, '1')
+        i6 = int_mul(i0, 8)
+        i7 = raw_load(i2, i6, descr=intarraydescr)
+        i8 = raw_load(i3, i6, descr=intarraydescr)
+        i9 = int_add(i7, i8)
+        raw_store(i4, i6, i9, descr=intarraydescr)
+        i11 = int_add(i0, 1)
+        i12 = int_lt(i11, i1)
+        guard_true(i12) [i4, i3, i2, i1, i11]
+        debug_merge_point(0, 0, '2')
+        label(i11, i1, i2, i3, i4)
         """
         vopt = self.schedule(self.parse_loop(ops),1)
         self.debug_print_operations(vopt.loop)
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
@@ -32,18 +32,15 @@
         else:
             print ""
 
-def must_unpack_result_to_exec(var, op):
+def must_unpack_result_to_exec(op, target_op):
     # TODO either move to resop or util
-    if op.vector == -1:
-        return True
-    if op.getopnum() == rop.RAW_LOAD or \
-       op.getopnum() == rop.GETARRAYITEM_GC or \
-       op.getopnum() == rop.GETARRAYITEM_RAW:
-        return True
-    if op.getopnum() == rop.RAW_STORE or \
-       op.getopnum() == rop.SETARRAYITEM_GC or \
-       op.getopnum() == rop.SETARRAYITEM_RAW:
-        if op.getarg(1) == var:
+    if op.vector != -1:
+        return False
+    return True
+
+def prohibit_packing(op1, op2):
+    if op2.is_array_op():
+        if op2.getarg(1) == op1.result:
             return True
     return False
 
@@ -147,9 +144,7 @@
                     try:
                         value = rename_map[arg]
                         copied_op.setarg(i, value)
-                        print "rename", arg, " to ", value
                     except KeyError:
-                        print "failing", arg, i
                         pass
                 # not only the arguments, but also the fail args need
                 # to be adjusted. rd_snapshot stores the live variables
@@ -191,6 +186,7 @@
                 print "box", box, "=>", value
             except KeyError:
                 print "FAIL:", i, box
+                pass
 
         snapshot = Snapshot(self.clone_snapshot(snapshot.prev, rename_map),
                             new_boxes)
@@ -235,9 +231,24 @@
         self.combine_packset()
         self.schedule()
 
+    def relax_guard_dependencies(self):
+        int_mod = IntegralMod()
+        for idx, guard in self.vec_info.guards.items():
+            int_mod.reset()
+            for dep in self.dependency_graph.depends(idx):
+                op = self.operations[dep.idx_from]
+                if op.returns_bool_result():
+                    for arg in op.getarglist():
+                        if isinstance(arg, Box):
+                            self._track_integral_modification(arg)
+
+    def _track_integral_modification(self, arg):
+        ref = MemoryRef(None, arg, None)
+
     def build_dependency_graph(self):
         self.dependency_graph = \
             DependencyGraph(self.loop.operations, self.vec_info.memory_refs)
+        self.relax_guard_dependencies()
 
     def find_adjacent_memory_refs(self):
         """ the pre pass already builds a hash of memory references and the
@@ -323,6 +334,8 @@
         end_ij = len(self.packset.packs)
         while True:
             len_before = len(self.packset.packs)
+            print "loop", len_before
+            i = 0
             while i < end_ij:
                 while j < end_ij and i < end_ij:
                     if i == j:
@@ -335,6 +348,7 @@
                     elif pack2.rightmost_match_leftmost(pack1):
                         end_ij = self.packset.combine(j,i)
                     j += 1
+                j = 0
                 i += 1
             if len_before == len(self.packset.packs):
                 break
@@ -500,18 +514,25 @@
         into account the benefit of executing this instruction
         as SIMD instruction.
         """
-        savings = -1 # 1 point for loading and 1 point for storing
+        savings = -1
 
-        # without loss of generatlity: only check the left side
+        # without loss of generatlity: only check 'left' operation
         lop = self.operations[lopidx]
         target_op = self.operations[pack.left.opidx]
 
+        if prohibit_packing(lop, target_op):
+            return -1
+
         if not expand_forward:
-            if not must_unpack_result_to_exec(lop.result, target_op):
+            print " backward savings", savings
+            if not must_unpack_result_to_exec(target_op, lop):
                 savings += 1
+            print " => backward savings", savings
         else:
-            if not must_unpack_result_to_exec(target_op.result, lop):
+            print " forward savings", savings
+            if not must_unpack_result_to_exec(target_op, lop):
                 savings += 1
+            print " => forward savings", savings
 
         return savings
 
@@ -595,15 +616,25 @@
     def __init__(self):
         self.smallest_type_bytes = 0
         self.memory_refs = {}
+        self.guards = {}
         self.track_memory_refs = False
         self.index = 0
 
+    guard_source = """
+    def operation_{name}(self, op):
+        if self.track_memory_refs:
+            self.guards[self.index] = op
+    """
+    for op in ['GUARD_TRUE','GUARD_FALSE']:
+            exec py.code.Source(guard_source.format(name=op)).compile()
+    del guard_source
+
     array_access_source = """
     def operation_{name}(self, op):
         descr = op.getdescr()
         if self.track_memory_refs:
             self.memory_refs[self.index] = \
-                    MemoryRef(op.getarg(0), op.getarg(1), op.getdescr())
+                MemoryRef(op.getarg(0), op.getarg(1), op.getdescr(), {elemidx})
         if not descr.is_array_of_pointers():
             byte_count = descr.get_item_size_in_bytes()
             if self.smallest_type_bytes == 0 \
@@ -611,17 +642,17 @@
                 self.smallest_type_bytes = byte_count
     """
     exec py.code.Source(array_access_source
-              .format(name='RAW_LOAD')).compile()
+              .format(name='RAW_LOAD',elemidx=True)).compile()
     exec py.code.Source(array_access_source
-              .format(name='RAW_STORE')).compile()
+              .format(name='RAW_STORE',elemidx=True)).compile()
     exec py.code.Source(array_access_source
-              .format(name='GETARRAYITEM_GC')).compile()
+              .format(name='GETARRAYITEM_GC',elemidx=False)).compile()
     exec py.code.Source(array_access_source
-              .format(name='SETARRAYITEM_GC')).compile()
+              .format(name='SETARRAYITEM_GC',elemidx=False)).compile()
     exec py.code.Source(array_access_source
-              .format(name='GETARRAYITEM_RAW')).compile()
+              .format(name='GETARRAYITEM_RAW',elemidx=False)).compile()
     exec py.code.Source(array_access_source
-              .format(name='SETARRAYITEM_RAW')).compile()
+              .format(name='SETARRAYITEM_RAW',elemidx=False)).compile()
     del array_access_source
 
     def default_operation(self, operation):
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -171,6 +171,11 @@
     def is_vector_arithmetic(self):
         return rop._VEC_ARITHMETIC_FIRST <= self.getopnum() <= rop._VEC_ARITHMETIC_LAST
 
+    def is_array_op(self):
+        on = self.getopnum()
+        return rop.GETARRAYITEM_GC <= on <= rop.VEC_RAW_LOAD or \
+               rop.SETARRAYITEM_GC <= on <= rop.VEC_RAW_STORE
+
     def is_comparison(self):
         return self.is_always_pure() and self.returns_bool_result()
 
@@ -500,9 +505,9 @@
 
     'GETARRAYITEM_GC/2d',
     'GETARRAYITEM_RAW/2d',
-    'GETINTERIORFIELD_GC/2d',
     'RAW_LOAD/2d',
     'VEC_RAW_LOAD/3d',
+    'GETINTERIORFIELD_GC/2d',
     'GETFIELD_GC/1d',
     'GETFIELD_RAW/1d',
     '_MALLOC_FIRST',
@@ -523,10 +528,10 @@
     'INCREMENT_DEBUG_COUNTER/1',
     'SETARRAYITEM_GC/3d',
     'SETARRAYITEM_RAW/3d',
+    'RAW_STORE/3d',
+    'VEC_RAW_STORE/4d',
     'SETINTERIORFIELD_GC/3d',
     'SETINTERIORFIELD_RAW/3d',    # right now, only used by tests
-    'RAW_STORE/3d',
-    'VEC_RAW_STORE/4d',
     'SETFIELD_GC/2d',
     'ZERO_PTR_FIELD/2', # only emitted by the rewrite, clears a pointer field
                         # at a given constant offset, no descr
diff --git a/rpython/jit/metainterp/test/test_vectorize.py b/rpython/jit/metainterp/test/test_vectorize.py
--- a/rpython/jit/metainterp/test/test_vectorize.py
+++ b/rpython/jit/metainterp/test/test_vectorize.py
@@ -8,7 +8,7 @@
 from rpython.rlib.jit import JitDriver, hint, set_param
 from rpython.rlib.objectmodel import compute_hash
 from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib.rarithmetic import r_uint
+from rpython.rlib.rarithmetic import r_uint, intmask
 from rpython.rlib.rawstorage import (alloc_raw_storage, raw_storage_setitem,
                                      free_raw_storage, raw_storage_getitem)
 
@@ -24,7 +24,7 @@
     def test_vectorize_simple_load_arith_store_mul(self):
         myjitdriver = JitDriver(greens = [],
                                 reds = ['i','d','va','vb','vc'],
-                                vectorize=True)
+                                vectorize=False)
         def f(d):
             va = alloc_raw_storage(d*rffi.sizeof(rffi.SIGNED), zero=True)
             vb = alloc_raw_storage(d*rffi.sizeof(rffi.SIGNED), zero=True)
@@ -96,7 +96,7 @@
         self.check_trace_count(1)
 
     def test_guard(self):
-        pytest.skip()
+        py.test.skip('abc')
         myjitdriver = JitDriver(greens = [],
                                 reds = ['a','b','c'],
                                 vectorize=True)
@@ -117,5 +117,40 @@
         assert res == 42
         self.check_trace_count(1)
 
+    @py.test.mark.parametrize('i',[8])
+    def test_vectorize_array_get_set(self,i):
+        myjitdriver = JitDriver(greens = [],
+                                reds = ['i','d','va','vb','vc'],
+                                vectorize=True)
+        ET = rffi.SIGNED
+        T = lltype.Array(ET, hints={'nolength': True})
+        def f(d):
+            i = 0
+            va = lltype.malloc(T, d, flavor='raw', zero=True)
+            vb = lltype.malloc(T, d, flavor='raw', zero=True)
+            vc = lltype.malloc(T, d, flavor='raw', zero=True)
+            for j in range(d):
+                va[j] = j
+                vb[j] = j
+            while i < d:
+                myjitdriver.can_enter_jit(i=i, d=d, va=va, vb=vb, vc=vc)
+                myjitdriver.jit_merge_point(i=i, d=d, va=va, vb=vb, vc=vc)
+
+                a = va[i]
+                b = vb[i]
+                vc[i] = a+b
+
+                i += 1
+            res = 0
+            for j in range(d):
+                res += intmask(vc[j])
+            lltype.free(va, flavor='raw')
+            lltype.free(vb, flavor='raw')
+            lltype.free(vc, flavor='raw')
+            return res
+        res = self.meta_interp(f, [i])
+        assert res == f(i)
+        self.check_trace_count(1)
+
 class TestLLtype(VectorizeTest, LLJitMixin):
     pass


More information about the pypy-commit mailing list