[pypy-commit] pypy vecopt-merge: do not store the version on the descr anymore, but on an external data structure just for this purpose

plan_rich noreply at buildbot.pypy.org
Mon Aug 24 17:51:08 CEST 2015


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt-merge
Changeset: r79207:89a3655d9226
Date: 2015-08-24 17:34 +0200
http://bitbucket.org/pypy/pypy/changeset/89a3655d9226/

Log:	do not store the version on the descr anymore, but on an external
	data structure just for this purpose

diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -194,30 +194,34 @@
     if loop.versions:
         # compile each version once for the first fail descr!
         # this assumes that the root trace (= loop) is already compiled
-        to_stitch = []
-        for version in loop.versions:
-            if not version.faildescrs:
+        compiled = {}
+        info = loop.version_info
+        for descr in info.descrs:
+            print "$>", descr
+            version = info.get(descr)
+            if not version:
+                # the guard might have been removed from the trace
                 continue
-            faildescr = version.faildescrs[0]
-            assert isinstance(faildescr, ResumeGuardDescr)
-            vl = create_empty_loop(metainterp)
-            vl.inputargs = version.inputargs
-            vl.operations = version.operations
-            vl.original_jitcell_token = jitcell_token
-            asminfo = send_bridge_to_backend(jitdriver_sd, metainterp_sd,
-                                   faildescr, version.inputargs,
-                                   version.operations, jitcell_token)
-            record_loop_or_bridge(metainterp_sd, vl)
-            assert asminfo is not None
+            if version not in compiled:
+                print " +COMPILE", version
+                assert isinstance(descr, ResumeGuardDescr)
+                vl = create_empty_loop(metainterp)
+                vl.inputargs = version.inputargs
+                vl.operations = version.operations
+                vl.original_jitcell_token = jitcell_token
+                asminfo = send_bridge_to_backend(jitdriver_sd, metainterp_sd,
+                                                 descr, version.inputargs,
+                                                 version.operations, jitcell_token)
+                record_loop_or_bridge(metainterp_sd, vl)
+                assert asminfo is not None
+                compiled[version] = (asminfo, descr, version, jitcell_token)
+            else:
+                print " +stitch", version
+                param = compiled[version]
+                cpu.stitch_bridge(descr, param)
 
-            for i,fd in enumerate(version.faildescrs):
-                if i == 0:
-                    continue
-                to_stitch.append((fd, (asminfo, faildescr, version, jitcell_token)))
-        # stitch to the trace loop
-        for fd, param in to_stitch:
-            cpu.stitch_bridge(fd, param)
     loop.versions = None
+    loop.version_info = None
 
 def compile_retrace(metainterp, greenkey, start,
                     inputargs, jumpargs,
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -739,41 +739,72 @@
                 pass_by -= 1
     return -1
 
+class VersionInfo(object):
+    def __init__(self):
+        self.descrs = []
+        self.leads_to = {}
+        self.insert_index = -1
+
+    def mark(self):
+        self.insert_index = len(self.descrs)
+
+    def clear(self):
+        self.insert_index = -1
+
+    def track(self, op, descr, version):
+        #print "+++", descr, "=>", version
+        assert descr.loop_version()
+        if self.insert_index >= 0:
+            assert self.insert_index >= 0
+            self.descrs.insert(self.insert_index, descr)
+        else:
+            self.descrs.append(descr)
+        self.leads_to[descr] = version
+        # note: stitching a guard must resemble the order of the label
+        # otherwise a wrong mapping is handed to the register allocator
+        op.setfailargs(version.renamed_inputargs)
+        assert version.renamed_inputargs is not None
+
+    def remove(self, descr):
+        if descr in self.leads_to:
+            #print "---", descr, "=>", self.leads_to[descr]
+            del self.leads_to[descr]
+        else:
+            assert 0, "could not remove %s" % descr
+
+    def get(self, descr):
+        return self.leads_to.get(descr, None)
+
 class LoopVersion(object):
     """ A special version of a trace loop. Use loop.snaphost() to
         create one instance and attach it to a guard descr.
         If not attached to a descriptor, it will not be compiled.
     """
-    _compiled = (None,None,None,None)
     inputargs = None
     renamed_inputargs = None
 
     def __init__(self, operations):
-        self.faildescrs = None
-        self.stitchdescr = {}
         self.operations = operations
+        idx = index_of_first(rop.LABEL, self.operations)
+        assert idx >= 0
+        label = self.operations[idx]
+        self.inputargs = label.getarglist()
+        self.renamed_inputargs = label.getarglist()
 
-    def setup_once(self):
-        if self.operations:
-            idx = index_of_first(rop.LABEL, self.operations)
-            assert idx >= 0
-            label = self.operations[idx]
-            self.inputargs = label.getarglist()
-            self.renamed_inputargs = label.getarglist()
-            # register the faildescr for later stitching
-            for op in self.operations:
-                if op.is_guard():
-                    descr = op.getdescr()
-                    if descr.loop_version():
-                        self.faildescrs.append(descr)
-
-    def register_guard(self, op, descr, version):
-        assert descr.loop_version()
-        self.faildescrs.append(descr)
-        # note: stitching a guard must resemble the order of the label
-        # otherwise a wrong mapping is handed to the register allocator
-        op.setfailargs(version.renamed_inputargs)
-        assert version.renamed_inputargs is not None
+    def setup_once(self, info):
+        for op in self.operations:
+            if op.is_guard():
+                olddescr = op.getdescr()
+                if not olddescr:
+                    continue
+                descr = olddescr.clone()
+                op.setdescr(descr)
+                if descr.loop_version():
+                    toversion = info.leads_to.get(olddescr,None)
+                    if toversion:
+                        info.track(op, descr, toversion)
+                    else:
+                        assert 0, "olddescr must be found"
 
     def update_token(self, jitcell_token, all_target_tokens):
         # this is only invoked for versioned loops!
@@ -821,6 +852,7 @@
     def __init__(self, name):
         self.name = name
         self.versions = []
+        self.version_info = VersionInfo()
         # self.operations = list of ResOperations
         #   ops of the kind 'guard_xxx' contain a further list of operations,
         #   which may itself contain 'guard_xxx' and so on, making a tree.
@@ -858,6 +890,9 @@
         #
         self.operations = self.operations[:-1] + loop.operations
         self.versions = loop.versions
+        loop.versions = None
+        self.version_info = loop.version_info
+        loop.version_info = None
         if loop.quasi_immutable_deps:
             self.quasi_immutable_deps.update(loop.quasi_immutable_deps)
 
@@ -874,12 +909,24 @@
             return self.operations[index]
         return None
 
-    def snapshot(self, operations):
-        version = LoopVersion(operations)
-        version.setup_once()
+    def snapshot(self):
+        oplist = self.copy_operations(self.operations)
+        version = LoopVersion(oplist)
+        version.setup_once(self.version_info)
+        # register the faildescr for later stitching
         self.versions.append(version)
         return version
 
+    def copy_operations(self, operations):
+        ignore = (rop.DEBUG_MERGE_POINT,)
+        oplist = []
+        for op in operations:
+            if op.getopnum() in ignore:
+                continue
+            cloned = op.clone()
+            oplist.append(cloned)
+        return oplist
+
     def get_display_text(self):    # for graphpage.py
         return self.name + '\n' + repr(self.inputargs)
 
diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py
--- a/rpython/jit/metainterp/optimizeopt/guard.py
+++ b/rpython/jit/metainterp/optimizeopt/guard.py
@@ -148,10 +148,12 @@
         self.setoperation(guard)
         self.setcmp(cmp_op)
 
-    def set_to_none(self, operations):
+    def set_to_none(self, loop):
+        operations = loop.operations
         assert operations[self.index] is self.op
         operations[self.index] = None
-        #descr = self.op.getdescr()
+        descr = self.op.getdescr()
+        loop.version_info.remove(descr)
         #if descr and descr.loop_version():
         #    assert isinstance(descr, CompileLoopVersionDescr)
         #    descr.version = None
@@ -266,22 +268,19 @@
         self.collect_guard_information(loop)
         self.eliminate_guards(loop)
         #
-        if len(loop.versions) >= 2:
-            assert len(loop.versions) == 2
-            root_version = loop.versions[0]
-            version = loop.versions[1]
+        assert len(loop.versions) == 1
+        version = loop.versions[0]
 
-            for op in loop.operations:
-                if not op.is_guard():
-                    continue
-                descr = op.getdescr()
-                if descr.loop_version():
-                    assert isinstance(descr, ResumeGuardDescr)
-                    root_version.register_guard(op, descr, version)
+        for i,op in enumerate(loop.operations):
+            if not op.is_guard():
+                continue
+            descr = op.getdescr()
+            if descr and descr.loop_version():
+                assert isinstance(descr, ResumeGuardDescr)
+                loop.version_info.track(op, descr, version)
 
-            if user_code:
-                version = loop.snapshot(copy_operations(loop.operations))
-                self.eliminate_array_bound_checks(loop, root_version, version)
+        if user_code:
+            self.eliminate_array_bound_checks(loop)
 
     def emit_operation(self, op):
         self.renamer.rename(op)
@@ -290,7 +289,10 @@
     def operation_position(self):
         return len(self._newoperations)
 
-    def eliminate_array_bound_checks(self, loop, root_version, version):
+    def eliminate_array_bound_checks(self, loop):
+        info = loop.version_info
+        info.mark()
+        version = None
         self._newoperations = []
         for key, guards in self.strongest_guards.items():
             if len(guards) <= 1:
@@ -302,10 +304,13 @@
             for other in guards[1:]:
                 transitive_guard = one.transitive_imply(other, self, loop)
                 if transitive_guard:
-                    other.set_to_none(loop.operations)
+                    if version is None:
+                        version = loop.snapshot()
+                    other.set_to_none(loop)
                     descr = transitive_guard.getdescr()
                     assert isinstance(descr, ResumeGuardDescr)
-                    root_version.register_guard(transitive_guard, descr, version)
+                    info.track(transitive_guard, descr, version)
+        info.clear()
 
         if self.has_two_labels:
             oplist = [loop.operations[0]] + self._newoperations + \
@@ -315,23 +320,3 @@
             loop.operations = self._newoperations + \
                     [op for op in loop.operations if op]
 
-def copy_operations(operations):
-    ignore = (rop.DEBUG_MERGE_POINT,)
-    oplist = []
-    for op in operations:
-        if op.getopnum() in ignore:
-            continue
-        cloned = op.clone()
-        oplist.append(cloned)
-        if cloned.is_guard():
-            olddescr = cloned.getdescr()
-            if not olddescr:
-                continue
-            assert isinstance(olddescr, ResumeGuardDescr)
-            descr = olddescr.clone()
-            assert isinstance(descr, ResumeGuardDescr)
-            cloned.setdescr(descr)
-            if olddescr.loop_version():
-                # copy the version
-                descr.version = olddescr.version
-    return oplist
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
@@ -23,7 +23,7 @@
 from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleData,
         Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum,
         getunpackopnum, PackType, determine_input_output_types)
-from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt, copy_operations
+from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt
 from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp)
 from rpython.rlib import listsort
 from rpython.rlib.objectmodel import we_are_translated
@@ -42,7 +42,7 @@
     if user_code and user_loop_bail_fast_path(loop, warmstate):
         return
     # the original loop (output of optimize_unroll)
-    version = loop.snapshot(copy_operations(loop.operations))
+    version = loop.snapshot()
     try:
         debug_start("vec-opt-loop")
         metainterp_sd.logger_noopt.log_loop(loop.inputargs, loop.operations, -2, None, None, "pre vectorize")
@@ -505,7 +505,7 @@
             return
         if vector:
             # add accumulation info to the descriptor
-            for version in self.loop.versions[1:]:
+            for version in self.loop.versions:
                 # this needs to be done for renamed (accum arguments)
                 version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ]
             self.appended_arg_count = len(sched_data.invariant_vector_vars)


More information about the pypy-commit mailing list