[pypy-commit] pypy vecopt2: added test cases for the dependency graph and testing the calc of adjacent memory locations (not working yet)

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


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt2
Changeset: r77074:bb6417aa654c
Date: 2015-03-12 12:21 +0100
http://bitbucket.org/pypy/pypy/changeset/bb6417aa654c/

Log:	added test cases for the dependency graph and testing the calc of
	adjacent memory locations (not working yet)

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,10 +2,14 @@
 from rpython.jit.metainterp.resoperation import rop
 
 class Dependency(object):
-    def __init__(self, index, is_definition):
-        self.index = index
+    def __init__(self, ifrom, ito, is_definition):
+        self.ifrom = ifrom 
+        self.ito = ito
         self.is_definition = is_definition
 
+    def __repr__(self):
+        return 'dep(%d,%d)' % (self.ifrom, self.ito)
+
 class CrossIterationDependency(Dependency):
     pass
 
@@ -21,7 +25,7 @@
         self.loop = loop
         self.operations = loop.operations
         self.optimizer = optimizer
-        self.adjacent_list = [ [] ] * len(self.operations)
+        self.adjacent_list = [ [] for i in range(len(self.operations)) ]
 
         self.build_dependencies(loop.operations)
 
@@ -40,6 +44,7 @@
             if op.getopnum() == rop.LABEL:
                 for arg in op.getarglist():
                     defining_indices[arg] = 0
+                continue # prevent adding edge to the label itself
 
             # TODO what about a JUMP operation? it often has many parameters (10+) and uses
             # nearly every definition in the trace (for loops). Maybe we can skip this operation
@@ -55,8 +60,8 @@
                     self._put_edge(idx, i)
 
     def _put_edge(self, idx_from, idx_to):
-        self.adjacent_list[idx_from].append(Dependency(idx_to, True))
-        self.adjacent_list[idx_to].append(Dependency(idx_from, False))
+        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 instr_dependency(self, from_instr_idx, to_instr_idx):
         """ Does there exist a dependency from the instruction to another?
@@ -65,7 +70,7 @@
         """
         edges = self.adjacent_list[from_instr_idx]
         for edge in edges:
-            if edge.index == to_instr_idx:
+            if edge.ito == 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
@@ -8,7 +8,7 @@
 import rpython.jit.metainterp.optimizeopt.virtualize as virtualize
 from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph
 from rpython.jit.metainterp.optimizeopt.unroll import Inliner
-from rpython.jit.metainterp.optimizeopt.vectorize import OptVectorize
+from rpython.jit.metainterp.optimizeopt.vectorize import OptVectorize, MemoryRef
 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
@@ -58,18 +58,33 @@
 
     def assert_unroll_loop_equals(self, loop, expected_loop, \
                      unroll_factor = -1):
-        vec_optimizer = self.vec_optimizer(loop, unroll_factor)
+        vec_optimizer = self.vec_optimizer_unrolled(loop, unroll_factor)
         self.assert_equal(loop, expected_loop)
 
-    def assert_def_use(self, graph, from_instr_index, to_instr_index):
-        assert graph.instr_dependency(from_instr_index,
-                                      to_instr_index) is not None, \
-               " it is expected that instruction at index" + \
-               " %d depend on instr on index %d but it is not" \
-                    % (from_instr_index, to_instr_index)
+    def assert_no_edge(self, graph, f, t = -1):
+        if type(f) == list:
+            for _f,_t in f:
+                self.assert_no_edge(graph, _f, _t)
+        else:
+            assert graph.instr_dependency(f, t) is None, \
+                   " it is expected that instruction at index" + \
+                   " %d DOES NOT depend on instr on index %d but it does" \
+                        % (f, t)
+
+    def assert_def_use(self, graph, from_instr_index, to_instr_index = -1):
+
+        if type(from_instr_index) == list:
+            for f,t in from_instr_index:
+                self.assert_def_use(graph, f, t)
+        else:
+            assert graph.instr_dependency(from_instr_index,
+                                          to_instr_index) is not None, \
+                   " it is expected that instruction at index" + \
+                   " %d depends on instr on index %d but it is not" \
+                        % (from_instr_index, to_instr_index)
 
 class BaseTestDependencyGraph(DepTestHelper):
-    def test_simple(self):
+    def test_dependency_1(self):
         ops = """
         []
         i1 = int_add(1,1)
@@ -78,8 +93,13 @@
         jump()
         """
         dep_graph = self.build_dependency(ops)
-        self.assert_def_use(dep_graph, 1, 2)
-        self.assert_def_use(dep_graph, 2, 3)
+        self.assert_no_edge(dep_graph, [(i,i) for i in range(5)])
+        self.assert_def_use(dep_graph, [(1,2),(2,3)])
+        self.assert_no_edge(dep_graph, [(0,1), (1,3),
+                                        (0,2), (0,3),
+                                        (0,4), (1,3),
+                                        (2,4), (3,4)
+                                       ])
 
     def test_label_def_use_jump_use_def(self):
         ops = """
@@ -89,6 +109,7 @@
         jump(i1)
         """
         dep_graph = self.build_dependency(ops)
+        self.assert_no_edge(dep_graph, [(i,i) for i in range(4)])
         self.assert_def_use(dep_graph, 0, 1)
         self.assert_def_use(dep_graph, 1, 2)
         self.assert_def_use(dep_graph, 1, 3)
@@ -196,8 +217,8 @@
         jump(p0,i0)
         """
         vopt = self.vec_optimizer_unrolled(self.parse_loop(ops))
-        assert 1 in vopt.vec_info.array_ops
-        assert len(vopt.vec_info.array_ops) == 1
+        assert 1 in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 1
 
     def test_array_operation_indices_unrolled_1(self):
         ops = """
@@ -206,9 +227,55 @@
         jump(p0,i0)
         """
         vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),2)
-        assert 1 in vopt.vec_info.array_ops
-        assert 2 in vopt.vec_info.array_ops
-        assert len(vopt.vec_info.array_ops) == 2
+        assert 1 in vopt.vec_info.memory_refs
+        assert 2 in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 2
+
+    def test_array_operation_indices_unrolled_2(self):
+        ops = """
+        [p0,i0,i1]
+        i3 = raw_load(p0,i0,descr=chararraydescr)
+        i4 = raw_load(p0,i1,descr=chararraydescr)
+        jump(p0,i3,i4)
+        """
+        vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),1)
+        assert 1 in vopt.vec_info.memory_refs
+        assert 2 in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 2
+        vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),2)
+        for i in [1,2,3,4]:
+            assert i in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 4
+        vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),4)
+        for i in [1,2,3,4,5,6,7,8]:
+            assert i in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 8
+
+    def test_array_memory_ref_adjacent_1(self):
+        ops = """
+        [p0,i0]
+        i3 = raw_load(p0,i0,descr=chararraydescr)
+        i1 = int_add(i0,1)
+        jump(p0,i1)
+        """
+        vopt = self.vec_optimizer_unrolled(self.parse_loop(ops),2)
+        vopt.build_dependency_graph()
+        vopt.find_adjacent_memory_refs()
+        assert 1 in vopt.vec_info.memory_refs
+        assert 3 in vopt.vec_info.memory_refs
+        assert len(vopt.vec_info.memory_refs) == 2
+
+        mref1 = vopt.vec_info.memory_refs[1]
+        mref3 = vopt.vec_info.memory_refs[3]
+        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)
 
 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
@@ -3,6 +3,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 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
 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
@@ -28,6 +29,7 @@
         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):
         # fill the map with the renaming boxes. keys are boxes from the label
@@ -78,10 +80,10 @@
                     except KeyError:
                         pass
 
-                self._op_index = op_index
+                self.vec_info._op_index = op_index
                 iteration_ops.append(copied_op)
+                op_index += 1
                 self.vec_info.inspect_operation(copied_op)
-                op_index += 1
 
             # the jump arguments have been changed
             # if label(iX) ... jump(i(X+1)) is called, at the next unrolled loop
@@ -139,8 +141,23 @@
 
         self.unroll_loop_iterations(loop, unroll_factor)
 
+        self.build_dependencies()
+
         self.vectorized = True
 
+    def build_dependency_graph(self):
+        self.dependency_graph = DependencyGraph(self.optimizer,
+                                                self.optimizer.loop)
+
+    def find_adjacent_memory_refs(self):
+        """ the pre pass already builds a hash of memory references and the
+        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 = []
+        for opidx,memref in self.vec_info.memory_refs.items():
+            considered_vars.append(memref.origin)
+
     def vectorize_trace(self, loop):
         """ Implementation of the algorithm introduced by Larsen. Refer to
               '''Exploiting Superword Level Parallelism
@@ -163,11 +180,16 @@
     def __init__(self):
         self.smallest_type_bytes = 0
         self._op_index = 0
-        self.array_ops = []
+        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.array_ops.append(self._op_index)
+        self.memory_refs[self._op_index] = \
+                MemoryRef(op.getarg(0), op.getarg(1))
         if not descr.is_array_of_pointers():
             byte_count = descr.get_item_size_in_bytes()
             if self.smallest_type_bytes == 0 \
@@ -206,6 +228,8 @@
         self.offset = None
 
     def is_adjacent_to(self, mem_acc):
+        """ this is a symmetric relation """
+        return False
         if self.array == mem_acc.array:
             # TODO
             return self.offset == mem_acc.offset


More information about the pypy-commit mailing list