[pypy-commit] pypy vecopt2: impl & test memory adjacent calculation

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


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt2
Changeset: r77075:b794697698a8
Date: 2015-03-12 15:35 +0100
http://bitbucket.org/pypy/pypy/changeset/b794697698a8/

Log:	impl & test memory adjacent calculation

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,16 +2,14 @@
 from rpython.jit.metainterp.resoperation import rop
 
 class Dependency(object):
-    def __init__(self, ifrom, ito, is_definition):
-        self.ifrom = ifrom 
-        self.ito = ito
+    def __init__(self, idx_from, idx_to, arg, is_definition):
+        self.defined_arg = arg
+        self.idx_from = idx_from 
+        self.idx_to = idx_to
         self.is_definition = is_definition
 
     def __repr__(self):
-        return 'dep(%d,%d)' % (self.ifrom, self.ito)
-
-class CrossIterationDependency(Dependency):
-    pass
+        return 'dep(%d -> %d, defines? %d)' % (self.idx_from, self.idx_to, self.is_definition)
 
 class DependencyGraph(object):
     """ A graph that represents one of the following dependencies:
@@ -57,20 +55,23 @@
             for arg in op.getarglist():
                 if arg in defining_indices:
                     idx = defining_indices[arg]
-                    self._put_edge(idx, i)
+                    self._put_edge(idx, i, arg)
 
-    def _put_edge(self, idx_from, idx_to):
-        self.adjacent_list[idx_from].append(Dependency(idx_from, idx_to, True))
-        self.adjacent_list[idx_to].append(Dependency(idx_to, idx_from, False))
+    def _put_edge(self, idx_from, idx_to, arg):
+        self.adjacent_list[idx_from].append(Dependency(idx_from, idx_to, arg, True))
+        self.adjacent_list[idx_to].append(Dependency(idx_to, idx_from, arg, False))
+
+    def instr_dependencies(self, idx):
+        edges = self.adjacent_list[idx]
+        return edges
 
     def instr_dependency(self, from_instr_idx, to_instr_idx):
         """ Does there exist a dependency from the instruction to another?
             Returns None if there is no dependency or the Dependency object in
             any other case.
         """
-        edges = self.adjacent_list[from_instr_idx]
-        for edge in edges:
-            if edge.ito == to_instr_idx:
+        for edge in self.instr_dependencies(from_instr_idx):
+            if edge.idx_to == to_instr_idx:
                 return edge
         return None 
 
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
@@ -83,6 +83,14 @@
                    " %d depends on instr on index %d but it is not" \
                         % (from_instr_index, to_instr_index)
 
+    def assert_memory_ref_adjacent(self, m1, m2):
+        assert m1.is_adjacent_to(m2)
+        assert m2.is_adjacent_to(m1)
+
+    def assert_memory_ref_not_adjacent(self, m1, m2):
+        assert not m1.is_adjacent_to(m2)
+        assert not m2.is_adjacent_to(m1)
+
 class BaseTestDependencyGraph(DepTestHelper):
     def test_dependency_1(self):
         ops = """
@@ -259,7 +267,14 @@
         jump(p0,i1)
         """
         vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),2)
+        print()
+        for i,op in enumerate(vopt.optimizer.loop.operations):
+            print(i,op)
         vopt.build_dependency_graph()
+        self.assert_no_edge(vopt.dependency_graph, [(i,i) for i in range(6)])
+        self.assert_def_use(vopt.dependency_graph, [(0,1),(2,3),(4,5)])
+        self.assert_no_edge(vopt.dependency_graph, [(0,4),(0,0)])
+
         vopt.find_adjacent_memory_refs()
         assert 1 in vopt.vec_info.memory_refs
         assert 3 in vopt.vec_info.memory_refs
@@ -270,12 +285,44 @@
         assert isinstance(mref1, MemoryRef)
         assert isinstance(mref3, MemoryRef)
 
-        self.assert_no_edge(vopt.dependency_graph, [(i,i) for i in range(6)])
-        self.assert_def_use(vopt.dependency_graph, [(0,1),(2,3),(4,5)])
-        self.assert_no_edge(vopt.dependency_graph, [(0,4),(0,0)])
-
         assert mref1.is_adjacent_to(mref3)
         assert mref3.is_adjacent_to(mref1)
 
+    def test_array_memory_ref_not_adjacent_1(self):
+        ops = """
+        [p0,i0,i4]
+        i3 = raw_load(p0,i0,descr=chararraydescr)
+        i1 = int_add(i0,1)
+        i5 = raw_load(p0,i4,descr=chararraydescr)
+        i6 = int_add(i4,1)
+        jump(p0,i1,i6)
+        """
+        vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),2)
+        vopt.build_dependency_graph()
+        self.assert_no_edge(vopt.dependency_graph, [(i,i) for i in range(6)])
+        self.assert_def_use(vopt.dependency_graph, [(0,1),(0,2),(0,3),(0,4),(2,5)])
+        self.assert_no_edge(vopt.dependency_graph, [(1,3),(2,4)])
+
+        vopt.find_adjacent_memory_refs()
+
+        for i in [1,3,5,7]:
+            assert i in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 4
+
+        mref1 = vopt.vec_info.memory_refs[1]
+        mref3 = vopt.vec_info.memory_refs[3]
+        mref5 = vopt.vec_info.memory_refs[5]
+        mref7 = vopt.vec_info.memory_refs[7]
+        assert isinstance(mref1, MemoryRef)
+        assert isinstance(mref3, MemoryRef)
+        assert isinstance(mref5, MemoryRef)
+        assert isinstance(mref7, MemoryRef)
+
+        self.assert_memory_ref_adjacent(mref1, mref5)
+        self.assert_memory_ref_not_adjacent(mref1, mref3)
+        self.assert_memory_ref_not_adjacent(mref1, mref7)
+        self.assert_memory_ref_adjacent(mref3, mref7)
+
+
 class TestLLtype(BaseTestDependencyGraph, LLtypeMixin):
     pass
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
@@ -7,11 +7,17 @@
 from rpython.jit.metainterp.resoperation import rop
 from rpython.jit.metainterp.resume import Snapshot
 from rpython.rlib.debug import debug_print, debug_start, debug_stop
+from rpython.jit.metainterp.jitexc import JitException
+
+class NotAVectorizeableLoop(JitException):
+    def __str__(self):
+        return 'NotAVectorizeableLoop()'
 
 def optimize_vector(metainterp_sd, jitdriver_sd, loop, optimizations):
     opt = OptVectorize(metainterp_sd, jitdriver_sd, loop, optimizations)
-    opt_loop = opt.propagate_all_forward()
-    if not opt.vectorized:
+    try:
+        opt.propagate_all_forward()
+    except NotAVectorizeableLoop:
         # vectorization is not possible, propagate only normal optimizations
         def_opt = Optimizer(metainterp_sd, jitdriver_sd, loop, optimizations)
         def_opt.propagate_all_forward()
@@ -28,7 +34,6 @@
                                              loop, optimizations)
         self.vec_info = LoopVectorizeInfo()
         self.memory_refs = []
-        self.vectorized = False
         self.dependency_graph = None
 
     def _rename_arguments_ssa(self, rename_map, label_args, jump_args):
@@ -135,7 +140,7 @@
         byte_count = self.vec_info.smallest_type_bytes
         if byte_count == 0:
             # stop, there is no chance to vectorize this trace
-            return loop
+            raise NotAVectorizeableLoop()
 
         unroll_factor = self.get_estimated_unroll_factor()
 
@@ -143,8 +148,6 @@
 
         self.build_dependencies()
 
-        self.vectorized = True
-
     def build_dependency_graph(self):
         self.dependency_graph = DependencyGraph(self.optimizer,
                                                 self.optimizer.loop)
@@ -154,9 +157,40 @@
         operations. Since it is in SSA form there is no array index. Indices
         are flattend. If there are two array accesses in the unrolled loop
         i0,i1 and i1 = int_add(i0,c), then i0 = i0 + 0, i1 = i0 + 1 """
-        considered_vars = []
+        loop = self.optimizer.loop
+        operations = loop.operations
+        integral_mod = IntegralMod(self.optimizer)
         for opidx,memref in self.vec_info.memory_refs.items():
-            considered_vars.append(memref.origin)
+            print("trying ref", memref, "op idx", opidx)
+            while True:
+                op = operations[opidx]
+                if op.getopnum() == rop.LABEL:
+                    break
+
+                print("checking op at idx", opidx)
+                for dep in self.dependency_graph.instr_dependencies(opidx):
+                    # this is a use, thus if dep is not a defintion
+                    # it points back to the definition
+                    print(memref.origin, " == ", dep.defined_arg)
+                    if memref.origin == dep.defined_arg and not dep.is_definition:
+                        # if is_definition is false the params is swapped
+                        # idx_to attributes points to definer
+                        def_op = operations[dep.idx_to]
+                        opidx = dep.idx_to
+                        break
+                else:
+                    # this is an error in the dependency graph
+                    raise RuntimeError("a variable usage does not have a " +
+                             " definition. Cannot continue!")
+
+                print("reset")
+                integral_mod.reset()
+                print("inspect ", def_op)
+                integral_mod.inspect_operation(def_op)
+                if integral_mod.is_const_mod:
+                    integral_mod.update_memory_ref(memref)
+                else:
+                    break
 
     def vectorize_trace(self, loop):
         """ Implementation of the algorithm introduced by Larsen. Refer to
@@ -175,6 +209,51 @@
         # was not able to vectorize
         return False
 
+class IntegralMod(object):
+
+    def __init__(self, optimizer):
+        self.optimizer = optimizer
+        self.reset()
+
+    def reset(self):
+        self.is_const_mod = False
+        self.factor_c = 1
+        self.factor_d = 0
+        self.used_box = None
+
+    def operation_INT_ADD(self, op):
+        print("int_add")
+        box_a0 = op.getarg(0)
+        box_a1 = op.getarg(1)
+        a0 = self.optimizer.getvalue(box_a0)
+        a1 = self.optimizer.getvalue(box_a1)
+        if a0.is_constant() and a1.is_constant():
+            # this means that the overall array offset is not
+            # added to a variable, but is constant
+            self.is_const_mod = True
+            self.factor_d += box_a1.getint() + box_a0.getint()
+            self.used_box = None
+        elif a0.is_constant():
+            self.is_const_mod = True
+            self.factor_d += box_a0.getint()
+            self.used_box = box_a1
+        elif a1.is_constant():
+            self.is_const_mod = True
+            self.factor_d += box_a1.getint()
+            self.used_box = box_a0
+
+    def update_memory_ref(self, memref):
+        memref.factor_d = self.factor_d
+        memref.factor_c = self.factor_c
+        memref.origin = self.used_box
+        print("update", memref.factor_d, memref.factor_c, memref.origin)
+
+    def default_operation(self, operation):
+        pass
+integral_dispatch_opt = make_dispatcher_method(IntegralMod, 'operation_',
+        default=IntegralMod.default_operation)
+IntegralMod.inspect_operation = integral_dispatch_opt
+
 class LoopVectorizeInfo(object):
 
     def __init__(self):
@@ -183,13 +262,10 @@
         self.memory_refs = {}
         self.label_op = None
 
-    def operation_LABEL(self, op):
-        self.label = op
-
     def operation_RAW_LOAD(self, op):
         descr = op.getdescr()
         self.memory_refs[self._op_index] = \
-                MemoryRef(op.getarg(0), op.getarg(1))
+                MemoryRef(op.getarg(0), op.getarg(1), op.getdescr())
         if not descr.is_array_of_pointers():
             byte_count = descr.get_item_size_in_bytes()
             if self.smallest_type_bytes == 0 \
@@ -222,16 +298,22 @@
 
 
 class MemoryRef(object):
-    def __init__(self, array, origin):
+    def __init__(self, array, origin, descr):
         self.array = array
         self.origin = origin
-        self.offset = None
+        self.descr = descr
+        self.factor_c = 1
+        self.factor_d = 0
 
-    def is_adjacent_to(self, mem_acc):
+    def is_adjacent_to(self, other):
         """ this is a symmetric relation """
+        if self.array == other.array \
+            and self.origin == other.origin:
+            my_off = (self.factor_c * self.factor_d) 
+            other_off = (other.factor_c * other.factor_d)
+            diff = my_off - other_off
+            return diff == 1 or diff == -1
         return False
-        if self.array == mem_acc.array:
-            # TODO
-            return self.offset == mem_acc.offset
 
-
+    def __repr__(self):
+        return 'MemoryRef(%s,%s,%s)' % (self.origin, self.factor_c, self.factor_d)


More information about the pypy-commit mailing list