Author: Richard Plangger <r...@pasra.at> Branch: vecopt-merge Changeset: r78928:8bbff2ecdaa3 Date: 2015-08-11 19:18 +0200 http://bitbucket.org/pypy/pypy/changeset/8bbff2ecdaa3/
Log: started to refactor scheduling to remove the unnecessary list allocation each iteration diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -17,26 +17,13 @@ self.graph = graph self.schedulable_nodes = self.graph.schedulable_nodes self.sched_data = sched_data + self.oplist = None + self.renamer = None def has_more(self): return len(self.schedulable_nodes) > 0 - def next(self, renamer, position): - i = self._next(self.schedulable_nodes) - if i >= 0: - candidate = self.schedulable_nodes[i] - del self.schedulable_nodes[i] - return self.schedule(candidate, renamer, position) - - # it happens that packs can emit many nodes that have been - # added to the scheuldable_nodes list, in this case it could - # be that no next exists even though the list contains elements - if not self.has_more(): - return [] - - raise AssertionError("schedule failed cannot continue. possible reason: cycle") - - def _next(self, candidate_list): + def next_index(self, candidate_list): i = len(candidate_list)-1 while i >= 0: candidate = candidate_list[i] @@ -64,22 +51,8 @@ return False return candidate.depends_count() == 0 - def schedule(self, candidate, renamer, position): - if candidate.pack: - pack = candidate.pack - for node in pack.operations: - renamer.rename(node.getoperation()) - vops = self.sched_data.as_vector_operation(pack, renamer) - for node in pack.operations: - self.scheduled(node, position) - return vops - else: - self.scheduled(candidate, position) - renamer.rename(candidate.getoperation()) - return [candidate.getoperation()] - - def scheduled(self, node, position): - node.position = position + def scheduled(self, node): + node.position = len(self.oplist) for dep in node.provides()[:]: # COPY to = dep.to node.remove_edge_to(to) @@ -105,6 +78,26 @@ node.clear_dependencies() node.emitted = True + def emit_into(self, oplist, renamer, unpack=False): + self.renamer = renamer + self.oplist = oplist + self.unpack = unpack + while self.has_more(): + i = self.next_index(self.schedulable_nodes) + if i >= 0: + candidate = self.schedulable_nodes[i] + del self.schedulable_nodes[i] + self.sched_data.schedule_candidate(self, candidate) + continue + + # it happens that packs can emit many nodes that have been + # added to the scheuldable_nodes list, in this case it could + # be that no next exists even though the list contains elements + if not self.has_more(): + break + + raise AssertionError("schedule failed cannot continue. possible reason: cycle") + def vectorbox_outof_box(box, count=-1, size=-1, type='-'): if box.type not in (FLOAT, INT): raise AssertionError("cannot create vector box of type %s" % (box.type)) @@ -251,22 +244,6 @@ self.output_type = None self.costmodel = None - def check_if_pack_supported(self, pack): - op0 = pack.operations[0].getoperation() - if self.input_type is None: - # must be a load/guard op - return - insize = self.input_type.getsize() - if op0.casts_box(): - # prohibit the packing of signext calls that - # cast to int16/int8. - _, outsize = op0.cast_to() - self.sched_data._prevent_signext(outsize, insize) - if op0.getopnum() == rop.INT_MUL: - if insize == 8 or insize == 1: - # see assembler for comment why - raise NotAProfitableLoop - def as_vector_operation(self, pack, sched_data, oplist): self.sched_data = sched_data self.vecops = oplist @@ -298,6 +275,23 @@ def before_argument_transform(self, args): pass + def check_if_pack_supported(self, pack): + op0 = pack.operations[0].getoperation() + if self.input_type is None: + # must be a load/guard op + return + insize = self.input_type.getsize() + if op0.casts_box(): + # prohibit the packing of signext calls that + # cast to int16/int8. + _, outsize = op0.cast_to() + self.sched_data._prevent_signext(outsize, insize) + if op0.getopnum() == rop.INT_MUL: + if insize == 8 or insize == 1: + # see assembler for comment why + raise NotAProfitableLoop + + def transform_pack(self): op = self.pack.leftmost() args = op.getarglist() @@ -754,30 +748,89 @@ self.inputargs[arg] = None self.seen = {} - def _prevent_signext(self, outsize, insize): - if insize != outsize: - if outsize < 4 or insize < 4: - raise NotAProfitableLoop + def schedule_candidate(self, scheduler, candidate): + """ if you implement a scheduler this operations is called + to emit the actual operation into the oplist of the scheduler + """ + renamer = scheduler.renamer + if candidate.pack: + for node in candidate.pack.operations: + self.unpack_from_vector(candidate.getoperation(), renamer) + scheduler.scheduled(node) + #renamer.rename(node.getoperation()) + self.as_vector_operation(scheduler, candidate.pack) + else: + self.unpack_from_vector(candidate.getoperation(), renamer) + scheduler.scheduled(candidate) + #renamer.rename(candidate.getoperation()) + op = candidate.getoperation() + scheduler.oplist.append(op) - def as_vector_operation(self, pack, preproc_renamer): + def as_vector_operation(self, scheduler, pack): assert pack.opcount() > 1 # properties that hold for the pack are: # + isomorphism (see func above) # + tightly packed (no room between vector elems) - oplist = [] + oplist = scheduler.oplist + position = len(oplist) op = pack.operations[0].getoperation() determine_trans(op).as_vector_operation(pack, self, oplist) # + # XXX if pack.is_accumulating(): - box = oplist[0].result + box = oplist[position].result assert box is not None for node in pack.operations: op = node.getoperation() assert op.result is not None preproc_renamer.start_renaming(op.result, box) - # - return oplist + + def unpack_from_vector(self, op, renamer): + renamer.rename(op) + args = op.getarglist() + + # unpack for an immediate use + for i, arg in enumerate(op.getarglist()): + if isinstance(arg, Box): + argument = self._unpack_from_vector(i, arg, renamer) + if arg is not argument: + op.setarg(i, argument) + if op.result: + self.seen[op.result] = None + # unpack for a guard exit + if op.is_guard(): + fail_args = op.getfailargs() + for i, arg in enumerate(fail_args): + if arg and isinstance(arg, Box): + argument = self._unpack_from_vector(i, arg, renamer) + if arg is not argument: + fail_args[i] = argument + + def _unpack_from_vector(self, i, arg, renamer): + if arg in self.seen or arg.type == 'V': + return arg + (j, vbox) = self.getvector_of_box(arg) + if vbox: + if vbox in self.invariant_vector_vars: + return arg + arg_cloned = arg.clonebox() + self.seen[arg_cloned] = None + renamer.start_renaming(arg, arg_cloned) + self.setvector_of_box(arg_cloned, j, vbox) + cj = ConstInt(j) + ci = ConstInt(1) + opnum = getunpackopnum(vbox.gettype()) + unpack_op = ResOperation(opnum, [vbox, cj, ci], arg_cloned) + self.costmodel.record_vector_unpack(vbox, j, 1) + self.emit_operation(unpack_op) + return arg_cloned + return arg + + def _prevent_signext(self, outsize, insize): + if insize != outsize: + if outsize < 4 or insize < 4: + raise NotAProfitableLoop def getvector_of_box(self, arg): return self.box_to_vbox.get(arg, (-1, None)) 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 @@ -460,13 +460,7 @@ sched_data.seen[arg] = None break # - while scheduler.has_more(): - position = len(self._newoperations) - ops = scheduler.next(renamer, position) - for op in ops: - if vector: - self.unpack_from_vector(op, sched_data, renamer) - self.emit_operation(op) + scheduler.emit_into(self._newoperations, renamer, unpack=vector) # if not we_are_translated(): for node in self.dependency_graph.nodes: @@ -490,47 +484,6 @@ self.orig_label_args) self.clear_newoperations() - def unpack_from_vector(self, op, sched_data, renamer): - renamer.rename(op) - args = op.getarglist() - - # unpack for an immediate use - for i, arg in enumerate(op.getarglist()): - if isinstance(arg, Box): - argument = self._unpack_from_vector(i, arg, sched_data, renamer) - if arg is not argument: - op.setarg(i, argument) - if op.result: - sched_data.seen[op.result] = None - # unpack for a guard exit - if op.is_guard(): - fail_args = op.getfailargs() - for i, arg in enumerate(fail_args): - if arg and isinstance(arg, Box): - argument = self._unpack_from_vector(i, arg, sched_data, renamer) - if arg is not argument: - fail_args[i] = argument - - def _unpack_from_vector(self, i, arg, sched_data, renamer): - if arg in sched_data.seen or arg.type == 'V': - return arg - (j, vbox) = sched_data.getvector_of_box(arg) - if vbox: - if vbox in sched_data.invariant_vector_vars: - return arg - arg_cloned = arg.clonebox() - sched_data.seen[arg_cloned] = None - renamer.start_renaming(arg, arg_cloned) - sched_data.setvector_of_box(arg_cloned, j, vbox) - cj = ConstInt(j) - ci = ConstInt(1) - opnum = getunpackopnum(vbox.gettype()) - unpack_op = ResOperation(opnum, [vbox, cj, ci], arg_cloned) - self.costmodel.record_vector_unpack(vbox, j, 1) - self.emit_operation(unpack_op) - return arg_cloned - return arg - def analyse_index_calculations(self): ee_pos = self.loop.find_first_index(rop.GUARD_EARLY_EXIT) if len(self.loop.operations) <= 2 or ee_pos == -1: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit