Author: Richard Plangger <r...@pasra.at> Branch: vecopt2 Changeset: r77081:bcbdc469ac7c Date: 2015-03-17 17:16 +0100 http://bitbucket.org/pypy/pypy/changeset/bcbdc469ac7c/
Log: separated dependency graph testing from the vectorize optimization tests. added more test cases that check fail args of guards (extended impl as well) extended the test cases to check that no dependency edge duplication is happening added missing vectorize field for jiddriver_sd in the test suit for virtualstate (all tests passing now) 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 @@ -8,7 +8,9 @@ self.is_definition = is_definition def __repr__(self): - return 'dep(%d -> %d, defines? %d)' % (self.idx_from, self.idx_to, self.is_definition) + return 'Dep(trace[%d] -> trace[%d], arg: %s, def-use? %d)' \ + % (self.idx_from, self.idx_to, self.defined_arg, \ + self.is_definition) class DependencyGraph(object): """ A graph that represents one of the following dependencies: @@ -36,14 +38,16 @@ defining_indices = {} for i,op in enumerate(operations): - # the label operation defines all operations at the beginning of the loop + # the label operation defines all operations at the + # beginning of the loop 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 + # 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 and let jump NEVER move... if op.result is not None: # the trace is always in SSA form, thus it is neither possible to have a WAR @@ -55,9 +59,33 @@ idx = defining_indices[arg] self._put_edge(idx, i, arg) + if op.getfailargs(): + for arg in op.getfailargs(): + if arg in defining_indices: + idx = defining_indices[arg] + self._put_edge(idx, i, arg) + 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)) + if self._is_unique_dep(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 _is_unique_dep(self, idx_from, idx_to, arg): + """ Dependencies must be unique. It is not allowed + to have multiple dependencies. + e.g. label(i1) + i2 = int_add(i1,i1) + ... + + Only the label instr can only have one dep (0->1) even if it is + used twice in int_add. The same is true for the reverse dependency + (1<-0) at int_add. + """ + for dep in self.adjacent_list[idx_from]: + if dep.idx_from == idx_from and dep.idx_to == idx_to \ + and dep.defined_arg == arg: + return False + return True def instr_dependencies(self, idx): edges = self.adjacent_list[idx] diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py new file mode 100644 --- /dev/null +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -0,0 +1,144 @@ +import py + +from rpython.jit.metainterp.optimizeopt.test.test_util import ( + LLtypeMixin, BaseTest, FakeMetaInterpStaticData, convert_old_style_to_targets) +from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop +from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph, Dependency +from rpython.jit.metainterp.resoperation import rop, ResOperation + +class DepTestHelper(BaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unfold" + + def build_dependency(self, ops): + loop = self.parse_loop(ops) + return DependencyGraph(loop) + + def parse_loop(self, ops): + loop = self.parse(ops, postprocess=self.postprocess) + token = JitCellToken() + loop.operations = [ResOperation(rop.LABEL, loop.inputargs, None, + descr=TargetToken(token))] + loop.operations + if loop.operations[-1].getopnum() == rop.JUMP: + loop.operations[-1].setdescr(token) + return loop + + 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) + + def assert_dependant(self, graph, edge_list): + """ Check if all dependencies are met. for complex cases + adding None instead of a list of integers skips the test. + This checks both if a dependency forward and backward exists. + """ + assert len(edge_list) == len(graph.adjacent_list) + for idx,edges in enumerate(edge_list): + if edges is None: + continue + dependencies = graph.adjacent_list[idx] + for edge in edges: + dependency = graph.instr_dependency(idx,edge) + assert dependency is not None, \ + " it is expected that instruction at index" + \ + " %d depends on instr on index %d but it is not" \ + % (idx, edge) + dependencies.remove(dependency) + assert dependencies == [], \ + "dependencies unexpected %s" \ + % dependencies + +class BaseTestDependencyGraph(DepTestHelper): + def test_dependency_empty(self): + ops = """ + [] + jump() + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, [ [], [], ]) + + def test_dependency_of_constant_not_used(self): + ops = """ + [] + i1 = int_add(1,1) + jump() + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, [ [], [], [] ]) + + def test_dependency_simple(self): + ops = """ + [] + i1 = int_add(1,1) + i2 = int_add(i1,1) + guard_value(i2,3) [] + jump() + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, + [ [], [2], [1,3], [2], [], ]) + + def test_def_use_jump_use_def(self): + ops = """ + [i3] + i1 = int_add(i3,1) + guard_value(i1,0) [] + jump(i1) + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, + [ [1], [0,2,3], [1], [1] ]) + + def test_dependency_guard(self): + ops = """ + [i3] + i1 = int_add(1,1) + guard_value(i1,0) [i3] + jump(i3) + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, + [ [2,3], [2], [1,0], [0] ]) + + def test_no_edge_duplication(self): + ops = """ + [i1] + i2 = int_lt(i1,10) + guard_false(i2) [i1] + i3 = int_add(i1,i1) + jump(i3) + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, + [ [1,2,3], [0,2], [1,0], [0,4], [3] ]) + + def test_no_edge_duplication_in_guard_failargs(self): + ops = """ + [i1] + i2 = int_lt(i1,10) + guard_false(i2) [i1,i1,i2,i1,i2,i1] + jump(i1) + """ + dep_graph = self.build_dependency(ops) + self.assert_dependant(dep_graph, + [ [1,2,3], [0,2], [1,0], [0] ]) + +class TestLLtype(BaseTestDependencyGraph, LLtypeMixin): + pass 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 @@ -19,7 +19,7 @@ class FakeJitDriverStaticData(object): vectorize=True -class DepTestHelper(BaseTest): +class VecTestHelper(BaseTest): enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unfold" @@ -98,36 +98,7 @@ for i,op in enumerate(loop.operations): print(i,op) -class BaseTestDependencyGraph(DepTestHelper): - def test_dependency_1(self): - ops = """ - [] - i1 = int_add(1,1) - i2 = int_add(i1,1) - guard_value(i2,3) [] - jump() - """ - dep_graph = self.build_dependency(ops) - 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 = """ - [i3] - i1 = int_add(i3,1) - guard_value(i1,0) [] - 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) +class BaseTestVectorize(VecTestHelper): def test_vectorize_skip_impossible_1(self): """ this trace does not contain a raw load / raw store from an array """ @@ -544,5 +515,5 @@ self.assert_equal(loop, self.parse_loop(ops)) -class TestLLtype(BaseTestDependencyGraph, LLtypeMixin): +class TestLLtype(BaseTestVectorize, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -791,7 +791,9 @@ if hasattr(self, 'callinfocollection'): metainterp_sd.callinfocollection = self.callinfocollection # - optimize_trace(metainterp_sd, None, bridge, self.enable_opts) + class FakeJitDriverSD(object): + vectorize = False + optimize_trace(metainterp_sd, FakeJitDriverSD(), bridge, self.enable_opts) def optimize_bridge(self, loops, bridge, expected, expected_target='Loop', **boxvalues): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit