[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