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

Reply via email to