Author: Richard Plangger <r...@pasra.at> Branch: vecopt2 Changeset: r77109:c110482d24ca Date: 2015-04-09 16:34 +0200 http://bitbucket.org/pypy/pypy/changeset/c110482d24ca/
Log: work in progress refactoring dependencies to easier remove instructions 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 @@ -28,19 +28,48 @@ , (rop.GETFIELD_RAW, 0, 1) ] +class Path(object): + def __init__(self,path): + self.path = path + + def walk(self, idx): + self.path.append(idx) + + def clone(self): + return Path(self.path[:]) + +class OpWrapper(object): + def __init__(self, op, opidx): + self.op = op + self.opidx = opidx + + def getopnum(self): + return self.op.getopnum() + + def is_guard_early_exit(self): + return self.op.getopnum() == rop.GUARD_NO_EARLY_EXIT: + class Dependency(object): - def __init__(self, idx_from, idx_to, arg): - assert idx_from != idx_to + def __init__(self, at, to, arg): + assert at != to self.args = [] if arg is not None: - self.args.append(arg) + self.add_dependency(at, to, arg) + self.at = at + self.to = to - self.idx_from = idx_from - self.idx_to = idx_to + def add_dependency(self, at, arg): + self.args.append((at,arg)) + + def reverse_direction(self, ref): + """ if the parameter index is the same as idx_to then + this edge is in reverse direction. + """ + return self.to == ref def __repr__(self): - return 'Dep(trace[%d] -> trace[%d], arg: %s)' \ - % (self.idx_from, self.idx_to, self.args) + return 'Dep(T[%d] -> T[%d], arg: %s)' \ + % (self.at.opidx, self.to.opidx, self.args) class DefTracker(object): def __init__(self, memory_refs): @@ -103,9 +132,9 @@ the same element. """ def __init__(self, operations): - self.operations = operations + self.operations = [OpWrapper(op) for op in operations] self.memory_refs = {} - self.adjacent_list = [ [] for i in range(len(self.operations)) ] + self.adjacent_list = { op: [] for op in operations } self.schedulable_nodes = [0] # label is always scheduleable self.index_vars = {} self.guards = [] @@ -128,8 +157,12 @@ # beginning of the loop if op.getopnum() == rop.LABEL: # TODO is it valid that a label occurs at the end of a trace? + s = 0 + if self.operations[s+1].is_guard_early_exit(): + s = 1 + self.i_edge(0,1,label='L->EE') for arg in op.getarglist(): - tracker.define(arg, 0) + tracker.define(arg, s) #if isinstance(arg, BoxInt): # assert arg not in self.index_vars # self.index_vars[arg] = IndexVar(arg) @@ -163,7 +196,7 @@ if dep.idx_to > i: break else: - self._put_edge(i, jump_pos, None) + self._put_edge(jump_pos, i, jump_pos, None) def _build_guard_dependencies(self, guard_idx, guard_opnum, tracker): if guard_opnum >= rop.GUARD_NOT_INVALIDATED: @@ -195,7 +228,7 @@ def_idx = tracker.definition_index(var) for dep in self.provides(def_idx): if var in dep.args and dep.idx_to > guard_idx: - self._put_edge(guard_idx, dep.idx_to, var, force=True, label='prev('+str(var)+')') + self._put_edge(dep.idx_to, guard_idx, dep.idx_to, var, force=True, label='prev('+str(var)+')') except KeyError: pass # handle fail args @@ -204,7 +237,7 @@ for arg in op.getfailargs(): try: for def_idx in tracker.redefintions(arg): - dep = self._put_edge(def_idx, guard_idx, arg, label="fail") + dep = self._put_edge(guard_idx, def_idx, guard_idx, arg, label="fail") except KeyError: assert False # @@ -229,10 +262,10 @@ self._guard_inhert(prev_op_idx, guard_idx) def _guard_inhert(self, idx, guard_idx): - dep = self._put_edge(idx, guard_idx, None, label='inhert') + dep = self._put_edge(guard_idx, idx, guard_idx, None, label='inhert') for dep in self.provides(idx): if dep.idx_to > guard_idx: - self._put_edge(guard_idx, dep.idx_to, None, label='inhert') + self._put_edge(dep.idx_to, guard_idx, dep.idx_to, None, label='inhert') def _build_non_pure_dependencies(self, op, index, tracker): # self._update_memory_ref(op, index, tracker) @@ -262,8 +295,8 @@ for dep in self.provides(def_idx): if dep.idx_to >= index: break - self._put_edge(dep.idx_to, index, argcell, label='war') - self._put_edge(def_idx, index, argcell) + self._put_edge(index, dep.idx_to, index, argcell, label='war') + self._put_edge(index, def_idx, index, argcell) except KeyError: pass else: @@ -275,7 +308,7 @@ def _def_use(self, arg, index, tracker, argcell=None): try: def_idx = tracker.definition_index(arg, index, argcell) - self._put_edge(def_idx, index, arg) + self._put_edge(index, def_idx, index, arg) except KeyError: pass @@ -329,34 +362,41 @@ else: break # cannot go further, this might be the label, or a constant - def _put_edge(self, idx_from, idx_to, arg, force=False, label=None): - assert idx_from != idx_to - dep = self.directly_depends(idx_from, idx_to) - if not dep: - if force or 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) - if not we_are_translated() and label is not None: - dep.label = label + def i_edge(self, idx_at, idx_to, label=None): + self._i_edge(idx_at, idx_to, None, label=label) + + def _edge(self, at, to, arg, label=None): + assert at != to + dep = self.i_directly_depends(idx_from, idx_to) + if not dep or dep.at != at: + #if force or self.independent(idx_from, idx_to): + dep = Dependency(at, to, arg) + self.adjacent_list.setdefault(at,[]).append(dep) + self.adjacent_list.setdefault(to,[]).append(dep) + if not we_are_translated() and label is not None: + dep.label = label else: if arg not in dep.args: - dep.args.append(arg) + dep.add_dependency(at,to,arg) if not we_are_translated() and label is not None: l = getattr(dep,'label',None) if l is None: l = '' dep.label = l + ", " + label + def _i_edge(self, idx_at, idx_to, arg, label=None): + at = self.operations[idx_at] + to = self.operations[idx_to] + self._edge(at, to, arg, label) + def provides_count(self, idx): + # TODO i = 0 for _ in self.provides(idx): i += 1 return i def provides(self, idx): - return self.get_uses(idx) - def get_uses(self, idx): for dep in self.adjacent_list[idx]: if idx < dep.idx_to: yield dep @@ -368,17 +408,12 @@ return i def depends(self, idx): - return self.get_defs(idx) - def get_defs(self, idx): for dep in self.adjacent_list[idx]: if idx > dep.idx_from: yield dep def dependencies(self, idx): return self.adjacent_list[idx] - def instr_dependencies(self, idx): - edges = self.adjacent_list[idx] - return edges def independent(self, ai, bi): """ An instruction depends on another if there is a dependency path from @@ -403,19 +438,27 @@ stmt_indices.append(dep.idx_from) return True - def definition_dependencies(self, idx): - # XXX remove - deps = [] - for dep in self.adjacent_list[idx]: - for dep_def in self.adjacent_list[dep.idx_from]: - deps.append(dep_def) - return deps + def iterate_paths_backward(self, ai, bi): + if ai == bi: + return + if ai > bi: + ai, bi = bi, ai + worklist = [(Path([bi]),bi)] + while len(worklist) > 0: + path,idx = worklist.pop() + for dep in self.depends(idx): + if ai > dep.idx_from or dep.points_backward(): + # this points above ai (thus unrelevant) + continue + cloned_path = path.clone() + cloned_path.walk(dep.idx_from) + if dep.idx_from == ai: + yield cloned_path + else: + worklist.append((cloned_path,dep.idx_from)) 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? Returns None if there is no dependency or the Dependency object in any other case. @@ -427,16 +470,16 @@ return edge return None - def remove_depencency(self, follow_dep, point_to_idx): - """ removes a all dependencies that point to the second parameter. - it is assumed that the adjacent_list[point_to_idx] is not iterated - when calling this function. - """ - idx = follow_dep.idx_from - if idx == point_to_idx: - idx = follow_dep.idx_to - self.adjacent_list[idx] = [d for d in self.adjacent_list[idx] \ - if d.idx_to != point_to_idx and d.idx_from != point_to_idx] + def i_remove_dependency(self, idx_at, idx_to): + at = self.operations[idx_at] + to = self.operations[idx_to] + self.remove_dependency(at, to) + def remove_dependency(self, at, to): + """ Removes a all dependencies that point to 'to' """ + self.adjacent_list[at] = \ + [d for d in self.adjacent_list[at] if d.to != to] + self.adjacent_list[to] = \ + [d for d in self.adjacent_list[to] if d.at != at] def __repr__(self): graph = "graph([\n" @@ -473,6 +516,11 @@ if getattr(dep, 'label', None): label = '[label="%s"]' % dep.label dot += " n%d -> n%d %s;\n" % (i,dep.idx_to,label) + elif dep.idx_to == i and dep.idx_from > i: + label = '' + if getattr(dep, 'label', None): + label = '[label="%s"]' % dep.label + dot += " n%d -> n%d %s;\n" % (dep.idx_from,dep.idx_to,label) dot += "\n}\n" return dot raise NotImplementedError("dot cannot built at runtime") @@ -522,15 +570,19 @@ to_del = [] adj_list = self.graph.adjacent_list[node] for dep in adj_list: - self.graph.remove_depencency(dep, node) + self.graph.remove_dependency_by_index(node, dep.idx_to) + self.graph.remove_dependency_by_index(dep.idx_to, node) + print "remove", node, "<=>", dep.idx_to + if self.is_schedulable(dep.idx_to): + print "sched", dep.idx_to + self.schedulable_nodes.append(dep.idx_to) # for dep in self.graph.provides(node): candidate = dep.idx_to - if self.is_schedulable(dep.idx_to): - self.schedulable_nodes.append(dep.idx_to) self.graph.adjacent_list[node] = [] def is_schedulable(self, idx): + print "is sched", idx, "count:", self.graph.depends_count(idx), self.graph.adjacent_list[idx] return self.graph.depends_count(idx) == 0 class IntegralForwardModification(object): 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 @@ -923,6 +923,7 @@ def test_schedule_vectorized_trace_1(self): ops = """ [i0, i1, i2, i3, i4, i5, i6, i7] + guard_no_early_exit() [] i8 = raw_load(i3, i0, descr=intarraydescr) i9 = raw_load(i4, i0, descr=intarraydescr) i10 = int_add(i8, i9) @@ -935,6 +936,7 @@ jump(i12, i8, i9, i3, i4, i5, i10, i7) """ vopt = self.schedule(self.parse_loop(ops),1) + self.debug_print_operations(vopt.loop) class TestLLtype(BaseTestVectorize, LLtypeMixin): 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 @@ -61,6 +61,10 @@ def_opt = Optimizer(metainterp_sd, jitdriver_sd, loop, optimizations) def_opt.propagate_all_forward() +class OpWrapper(object): + def __init__(self, op, opidx): + self.op = op + class VectorizingOptimizer(Optimizer): """ Try to unroll the loop and find instructions to group """ @@ -131,6 +135,8 @@ operations = [] for i in range(1,op_count-1): + if loop.operations[i].getopnum() == rop.GUARD_FUTURE_CONDITION: + continue op = loop.operations[i].clone() operations.append(op) self.emit_unrolled_operation(op) @@ -152,6 +158,8 @@ rename_map[la] = ja # for op in operations: + if op.getopnum() in (rop.GUARD_NO_EARLY_EXIT, rop.GUARD_FUTURE_CONDITION): + continue # do not unroll this operation twice copied_op = op.clone() if copied_op.result is not None: # every result assigns a new box, thus creates an entry @@ -246,15 +254,6 @@ self.dependency_graph = DependencyGraph(self.loop.operations) self.relax_guard_dependencies() - def relax_guard_dependencies(self): - return - for guard_idx in self.dependency_graph.guards: - guard = self.operations[guard_idx] - for dep in self.dependency_graph.depends(idx): - op = self.operations[dep.idx_from] - if op.returns_bool_result(): - pass - 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 are no array indices. @@ -382,6 +381,59 @@ else: scheduler.schedule_later(0) + def relax_guard_dependencies(self): + early_exit_idx = 1 + operations = self.loop.operations + assert operations[early_exit_idx].getopnum() == \ + rop.GUARD_NO_EARLY_EXIT + target_guard = operations[early_exit_idx] + for guard_idx in self.dependency_graph.guards: + if guard_idx == early_exit_idx: + continue + guard = operations[guard_idx] + if guard.getopnum() not in (rop.GUARD_TRUE,rop.GUARD_FALSE): + continue + self.dependency_graph.edge(early_exit_idx, guard_idx, early_exit_idx, label='EE') + print "put", guard_idx, "=>", early_exit_idx + del_deps = [] + for path in self.dependency_graph.iterate_paths_backward(guard_idx, early_exit_idx): + op_idx = path.path[1] + print "path", path.path + op = operations[op_idx] + if fail_args_break_dependency(guard, guard_idx, target_guard, early_exit_idx, op, op_idx): + print " +>+>==> break", op_idx, "=>", guard_idx + del_deps.append(op_idx) + for dep_idx in del_deps: + self.dependency_graph.remove_dependency_by_index(dep_idx, guard_idx) + + del_deps = [] + for dep in self.dependency_graph.provides(early_exit_idx): + del_deps.append(dep.idx_to) + for dep_idx in del_deps: + self.dependency_graph.remove_dependency_by_index(1, dep_idx) + self.dependency_graph.edge(dep_idx, 0, dep_idx) + last_idx = len(operations) - 1 + self.dependency_graph.remove_dependency_by_index(0,1) + self.dependency_graph.edge(last_idx, early_exit_idx, last_idx) + +def fail_args_break_dependency(guard, guard_idx, target_guard, target_guard_idx, op, op_idx): + failargs = set(guard.getfailargs()) + new_failargs = set(target_guard.getfailargs()) + + print " args:", [op.result] + op.getarglist()[:], " &&& ", failargs, " !!! ", new_failargs + if op.is_array_op(): + return True + if op.result is not None: + arg = op.result + if arg not in failargs or \ + arg in failargs and arg in new_failargs: + return False + for arg in op.getarglist(): + if arg not in failargs or \ + arg in failargs and arg in new_failargs: + return False + return True + class VecScheduleData(SchedulerData): def __init__(self): self.box_to_vbox = {} _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit