[pypy-commit] pypy vecopt2: moved integral modification and memory ref to dependency.py. this is needed to get rid of dependencies between 2 set array at different indices (work in progress)

plan_rich noreply at buildbot.pypy.org
Tue May 5 09:45:42 CEST 2015


Author: Richard Plangger <rich at pasra.at>
Branch: vecopt2
Changeset: r77093:c328ba0e6929
Date: 2015-03-26 16:23 +0100
http://bitbucket.org/pypy/pypy/changeset/c328ba0e6929/

Log:	moved integral modification and memory ref to dependency.py. this is
	needed to get rid of dependencies between 2 set array at different
	indices (work in progress)

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
@@ -1,3 +1,4 @@
+from rpython.jit.metainterp.optimizeopt.util import MemoryRef
 from rpython.jit.metainterp.resoperation import rop
 from rpython.jit.codewriter.effectinfo import EffectInfo
 from rpython.jit.metainterp.history import BoxPtr, ConstPtr, ConstInt, BoxInt
@@ -12,7 +13,6 @@
                      , (rop.SETFIELD_GC, 0, -1)
                      , (rop.SETFIELD_RAW, 0, -1)
                      , (rop.ZERO_PTR_FIELD, 0, -1)
-                     , (rop.ZERO_PTR_FIELD, 0, -1)
                      , (rop.ZERO_ARRAY, 0, -1)
                      , (rop.STRSETITEM, 0, -1)
                      , (rop.UNICODESETITEM, 0, -1)
@@ -46,6 +46,41 @@
         return 'Dep(trace[%d] -> trace[%d], arg: %s)' \
                 % (self.idx_from, self.idx_to, self.args)
 
+class DefTracker(object):
+    def __init__(self, memory_refs):
+        self.memory_refs = memory_refs
+        self.defs = {}
+
+    def define(self, arg, index, argcell=None):
+        print "def", arg, "at", index, "cell", argcell
+        if arg in self.defs:
+            self.defs[arg].append((index,argcell))
+        else:
+            self.defs[arg] = [(index,argcell)]
+
+    def definition_index(self, arg, index, argcell=None):
+        def_chain = self.defs[arg]
+        if len(def_chain) == 1:
+            return def_chain[0][0]
+        else:
+            if argcell == None:
+                return def_chain[-1][0]
+            else:
+                i = len(def_chain)-1
+                try:
+                    mref = self.memory_refs[index]
+                    while i >= 0:
+                        def_index = def_chain[i][0]
+                        oref = self.memory_refs[def_index]
+                        if mref.indices_can_alias(oref):
+                            return def_index
+                        i -= 1
+                except KeyError:
+                    # when a key error is raised, this means
+                    # no information is available, assume the worst
+                    pass
+                return def_chain[-1][0]
+
 class DependencyGraph(object):
     """ A graph that represents one of the following dependencies:
           * True dependency
@@ -56,16 +91,19 @@
         Note that adjacent lists order their dependencies. They are ordered
         by the target instruction they point to if the instruction is
         a dependency.
+
+        memory_refs: a dict that contains indices of memory references
+        (load,store,getarrayitem,...). If none provided, the construction
+        is conservative. It will never dismiss dependencies of two
+        modifications of one array even if the indices can never point to
+        the same element.
     """
-    def __init__(self, operations):
+    def __init__(self, operations, memory_refs):
         self.operations = operations
+        self.memory_refs = memory_refs
         self.adjacent_list = [ [] for i in range(len(self.operations)) ]
-
         self.build_dependencies(self.operations)
-
-    def is_complex_object_load(self, op):
-        opnum = op.getopnum()
-        return rop._ALWAYS_PURE_LAST <= opnum and opnum <= rop._MALLOC_FIRST
+        self.integral_mod = IntegralMod()
 
     def build_dependencies(self, operations):
         """ This is basically building the definition-use chain and saving this
@@ -75,126 +113,119 @@
             Write After Read, Write After Write dependencies are not possible,
             the operations are in SSA form
         """
-        defining_indices = {}
-        complex_indices = {}
+        tracker = DefTracker(self.memory_refs)
 
         for i,op in enumerate(operations):
             # 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
+                    tracker.define(arg, 0)
                 continue # prevent adding edge to the label itself
 
+            # definition of a new variable
             if op.result is not None:
-                # the trace is always in SSA form, thus it is neither possible
-                # to have a WAR not a WAW dependency
-                defining_indices[op.result] = i
+                # In SSA form. Modifications get a new variable
+                tracker.define(op.result, i)
 
-            if self.is_complex_object_load(op):
-                self._reuse_complex_definitions(op, i, defining_indices, complex_indices)
-            elif op.getopnum() == rop.JUMP:
-                self._finish_building_graph(op, i, defining_indices, complex_indices)
-            else:
+            # usage of defined variables
+            if op.is_always_pure() or op.is_final():
                 # normal case every arguments definition is set
                 for arg in op.getarglist():
-                    self._def_use(arg, i, defining_indices)
+                    self._def_use(arg, i, tracker)
+            else:
+                self.update_memory_ref(op, i, integral_mod)
+                self.put_edges_for_complex_objects(op, i, tracker)
 
-            if op.getfailargs():
+            # guard specifics
+            if op.is_guard():
                 for arg in op.getfailargs():
-                    self._def_use(arg, i, defining_indices)
+                    self._def_use(arg, i, tracker)
+                if i > 0:
+                    self._guard_dependency(op, i, operations, tracker)
 
-            # a trace has store operations on complex operations
-            # (e.g. setarrayitem). in general only once cell is updated,
-            # and in theroy it could be tracked but for simplicity, the
-            # whole is marked as redefined, thus any later usage sees
-            # only this definition.
-            self._redefine_complex_modification(op, i, defining_indices,
-                                                complex_indices)
-            if op.is_guard() and i > 0:
-                self._guard_dependency(op, i, operations, defining_indices)
+    def update_memory_ref(self, op, index):
+        if index not in self.memory_refs:
+            return
+        memref = self.memory_refs[index]
+        self.integral_mod.reset()
+        while True:
+            for dep in self.get_defs(index):
+                op = operations[dep.idx_from]
+                if op.result == memref.origin:
+                    index = dep.idx_from
+                    break
+            else:
+                break # cannot go further, this might be the label, or a constant
+            self.integral_mod.inspect_operation(op)
+            if self.integral_mod.is_const_mod:
+                self.integral_mod.update_memory_ref(memref)
+            else:
+                break # an operation that is not tractable
 
-    def _finish_building_graph(self, jumpop, orig_index, defining_indices, complex_indices):
-        assert jumpop.getopnum() == rop.JUMP
-        for (cobj, obj_index),index in complex_indices.items():
-            try:
-                old_idx = defining_indices[cobj]
-                if old_idx < index:
-                    defining_indices[cobj] = index
-            except KeyError:
-                defining_indices[cobj] = index
+    def put_edges_for_complex_objects(self, op, index, tracker):
+        self.update_memory_ref(op, index)
+        if self.loads_from_complex_object(op):
+            # If this complex object load operation loads an index that has been
+            # modified, the last modification should be used to put a def-use edge.
+            for opnum, i, j in unrolling_iterable(LOAD_COMPLEX_OBJ):
+                if opnum == op.getopnum():
+                    cobj = op.getarg(i)
+                    index_var = op.getarg(j)
+                    self._def_use(cobj, index, tracker, argcell=index_var)
+                    self._def_use(index_var, index, tracker)
+        else:
+            for arg, argcell, destroyed in self._side_effect_argument(op):
+                if argcell is not None:
+                    # tracks the exact cell that is modified
+                    self._def_use(arg, index, tracker, argcell=argcell)
+                    self._def_use(argcell, index, tracker)
+                    if destroyed:
+                        tracker.define(arg, index, argcell=argcell)
+                else:
+                    if destroyed:
+                        # we cannot be sure that only a one cell is modified
+                        # assume the worst, this is a complete redefintion
+                        try:
+                            # A trace is not in SSA form, but this complex object
+                            # modification introduces a WAR/WAW dependency
+                            def_idx = tracker.definition_index(arg, index)
+                            for dep in self.get_uses(def_idx):
+                                if dep.idx_to >= index:
+                                    break
+                                self._put_edge(dep.idx_to, index, argcell)
+                            self._put_edge(def_idx, index, argcell)
+                        except KeyError:
+                            pass
+                    else:
+                        # not destroyed, just a normal use of arg
+                        self._def_use(arg, index, tracker)
 
-        for arg in jumpop.getarglist():
-            self._def_use(arg, orig_index, defining_indices)
-
-    def _reuse_complex_definitions(self, op, index, defining_indices, complex_indices):
-        """ If this complex object load operation loads an index that has been
-        modified, the last modification should be used to put a def-use edge.
-        """
-        for opnum, i, j in unrolling_iterable(LOAD_COMPLEX_OBJ):
-            if opnum == op.getopnum():
-                cobj = op.getarg(i)
-                index_var = op.getarg(j)
-                try:
-                    cindex = complex_indices[(cobj, index_var)]
-                    self._put_edge(cindex, index, cobj)
-                except KeyError:
-                    # not redefined, edge to the label(...) definition
-                    self._def_use(cobj, index, defining_indices)
-
-                # def-use for the index variable
-                self._def_use(index_var, index, defining_indices)
-
-    def _def_use(self, param, index, defining_indices):
+    def _def_use(self, arg, index, tracker, argcell=None):
         try:
-            def_idx = defining_indices[param]
-            self._put_edge(def_idx, index, param)
+            def_idx = tracker.definition_index(arg, index, argcell)
+            self._put_edge(def_idx, index, arg)
         except KeyError:
             pass
 
-    def _redefine_complex_modification(self, op, index, defining_indices, complex_indices):
-        if not op.has_no_side_effect():
-            for cobj, arg in self._destroyed_arguments(op):
-                if arg is not None:
-                    # tracks the exact cell that is modified
-                    try:
-                        cindex = complex_indices[(cobj,arg)]
-                        self._put_edge(cindex, index, cobj)
-                    except KeyError:
-                        pass
-                    complex_indices[(cobj,arg)] = index
-                else:
-                    # we cannot prove that only a cell is modified, but we have
-                    # to assume that many of them are!
-                    try:
-                        # put an edge from the def. and all later uses until this
-                        # instruction to this instruction
-                        def_idx = defining_indices[cobj]
-                        for dep in self.instr_dependencies(def_idx):
-                            if dep.idx_to >= index:
-                                break
-                            self._put_edge(dep.idx_to, index, arg)
-                        self._put_edge(def_idx, index, arg)
-                    except KeyError:
-                        pass
-
-    def _destroyed_arguments(self, op):
+    def _side_effect_argument(self, op):
         # if an item in array p0 is modified or a call contains an argument
         # it can modify it is returned in the destroyed list.
         args = []
-        if op.is_call() and op.getopnum() != rop.CALL_ASSEMBLER:
-            # free destroys an argument -> connect all uses & def with it
-            descr = op.getdescr()
-            extrainfo = descr.get_extra_info()
-            if extrainfo.oopspecindex == EffectInfo.OS_RAW_FREE:
-                args.append((op.getarg(1),None))
-        else:
+        if self.modifies_complex_object(op):
             for opnum, i, j in unrolling_iterable(MODIFY_COMPLEX_OBJ):
                 if op.getopnum() == opnum:
                     if j == -1:
-                        args.append((op.getarg(i), None))
+                        args.append((op.getarg(i), None, True))
                     else:
-                        args.append((op.getarg(i), op.getarg(j)))
+                        args.append((op.getarg(i), op.getarg(j), True))
+                    break
+        else:
+            # assume this destroys every argument... can be enhanced by looking
+            # at the effect info of a call for instance
+            for arg in op.getarglist():
+                args.append((arg,None,True))
+
         return args
 
     def _guard_dependency(self, op, i, operations, defining_indices):
@@ -329,4 +360,184 @@
         self.adjacent_list[ia] = depb
         self.adjacent_list[ib] = depa
 
+    def loads_from_complex_object(self, op):
+        opnum = op.getopnum()
+        return rop._ALWAYS_PURE_LAST <= opnum and opnum <= rop._MALLOC_FIRST
 
+    def modifies_complex_object(self, op):
+        opnum = op.getopnum()
+        return rop.SETARRAYITEM_GC<= opnum and opnum <= rop.UNICODESETITEM
+
+
+# Utilities for array references.
+# Needed by dependency.py and vectorize.py
+# ____________________________________________________________
+
+class IntegralMod(object):
+    """ Calculates integral modifications on an integer object.
+    The operations must be provided in backwards direction and of one
+    variable only. Call reset() to reuse this object for other variables.
+    See MemoryRef for an example.
+    """
+
+    def __init__(self, optimizer):
+        self.optimizer = optimizer
+        self.reset()
+
+    def reset(self):
+        self.is_const_mod = False
+        self.coefficient_mul = 1
+        self.coefficient_div = 1
+        self.constant = 0
+        self.used_box = None
+
+    def _update_additive(self, i):
+        return (i * self.coefficient_mul) / self.coefficient_div
+
+    def is_const_integral(self, box):
+        if isinstance(box, ConstInt):
+            return True
+        return False
+
+    additive_func_source = """
+    def operation_{name}(self, op):
+        box_a0 = op.getarg(0)
+        box_a1 = op.getarg(1)
+        a0 = self.optimizer.getvalue(box_a0)
+        a1 = self.optimizer.getvalue(box_a1)
+        self.is_const_mod = True
+        if self.is_const_integral(a0) and self.is_const_integral(a1):
+            self.used_box = None
+            self.constant += self._update_additive(box_a0.getint() {op} \
+                                                      box_a1.getint())
+        elif self.is_const_integral(a0):
+            self.constant {op}= self._update_additive(box_a0.getint())
+            self.used_box = box_a1
+        elif self.is_const_integral(a1):
+            self.constant {op}= self._update_additive(box_a1.getint())
+            self.used_box = box_a0
+        else:
+            self.is_const_mod = False
+    """
+    exec py.code.Source(additive_func_source.format(name='INT_ADD', 
+                                                    op='+')).compile()
+    exec py.code.Source(additive_func_source.format(name='INT_SUB', 
+                                                    op='-')).compile()
+    del additive_func_source
+
+    multiplicative_func_source = """
+    def operation_{name}(self, op):
+        box_a0 = op.getarg(0)
+        box_a1 = op.getarg(1)
+        a0 = self.optimizer.getvalue(box_a0)
+        a1 = self.optimizer.getvalue(box_a1)
+        self.is_const_mod = True
+        if self.is_const_integral(a0) and self.is_const_integral(a1):
+            # here this factor becomes a constant, thus it is
+            # handled like any other additive operation
+            self.used_box = None
+            self.constant += self._update_additive(box_a0.getint() {cop} \
+                                                      box_a1.getint())
+        elif a0.is_constant():
+            self.coefficient_{tgt} {op}= box_a0.getint()
+            self.used_box = box_a1
+        elif self.is_const_integral(a1):
+            self.coefficient_{tgt} {op}= box_a1.getint()
+            self.used_box = box_a0
+        else:
+            self.is_const_mod = False
+    """
+    exec py.code.Source(multiplicative_func_source.format(name='INT_MUL', 
+                                                 op='*', tgt='mul',
+                                                 cop='*')).compile()
+    exec py.code.Source(multiplicative_func_source.format(name='INT_FLOORDIV',
+                                                 op='*', tgt='div',
+                                                 cop='/')).compile()
+    exec py.code.Source(multiplicative_func_source.format(name='UINT_FLOORDIV',
+                                                 op='*', tgt='div',
+                                                 cop='/')).compile()
+    del multiplicative_func_source
+
+    def update_memory_ref(self, memref):
+        memref.constant = self.constant
+        memref.coefficient_mul = self.coefficient_mul
+        memref.coefficient_div = self.coefficient_div
+        memref.origin = self.used_box
+
+    def default_operation(self, operation):
+        pass
+integral_dispatch_opt = make_dispatcher_method(IntegralMod, 'operation_',
+        default=IntegralMod.default_operation)
+IntegralMod.inspect_operation = integral_dispatch_opt
+del integral_dispatch_opt
+
+class MemoryRef(object):
+    """ a memory reference to an array object. IntegralMod is able
+    to propagate changes to this object if applied in backwards direction.
+    Example:
+
+    i1 = int_add(i0,1)
+    i2 = int_mul(i1,2)
+    setarrayitem_gc(p0, i2, 1, ...)
+
+    will result in the linear combination i0 * (2/1) + 2
+    """
+    def __init__(self, array, origin, descr):
+        self.array = array
+        self.origin = origin
+        self.descr = descr
+        self.coefficient_mul = 1
+        self.coefficient_div = 1
+        self.constant = 0
+
+    def is_adjacent_to(self, other):
+        """ this is a symmetric relation """
+        match, off = self.calc_difference(other)
+        if match:
+            return off == 1 or off == -1
+        return False
+
+    def is_adjacent_after(self, other):
+        """ the asymetric relation to is_adjacent_to """
+        match, off = self.calc_difference(other)
+        if match:
+            return off == 1
+        return False
+
+    def indices_can_alias(self, other):
+        """ can to array indices alias? they can alias iff 
+        self.origin != other.origin, or their
+        linear combination point to the same element.
+        """
+        match, off = self.calc_difference(other)
+        if match:
+            return off != 0
+        return False
+
+    def __eq__(self, other):
+        match, off = self.calc_difference(other)
+        if match:
+            return off == 0
+        return False
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def accesses_same_object(self, other):
+        assert isinstance(other, MemoryRef)
+        return self.array == other.array
+
+    def calc_difference(self, other):
+        assert isinstance(other, MemoryRef)
+        if self.array == other.array \
+            and self.origin == other.origin:
+            mycoeff = self.coefficient_mul // self.coefficient_div
+            othercoeff = other.coefficient_mul // other.coefficient_div
+            diff = other.constant - self.constant
+            return mycoeff == othercoeff, diff
+        return False, 0
+
+    def __repr__(self):
+        return 'MemoryRef(%s*(%s/%s)+%s)' % (self.origin, self.coefficient_mul,
+                                            self.coefficient_div, self.constant)
+
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py
@@ -3,14 +3,20 @@
 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.optimizeopt.dependency import (DependencyGraph, Dependency,
+        IntegralMod)
 from rpython.jit.metainterp.resoperation import rop, ResOperation
 
 class DepTestHelper(BaseTest):
 
-    def build_dependency(self, ops):
+    def build_dependency(self, ops, memory_refs = False):
         loop = self.parse_loop(ops)
-        self.last_graph = DependencyGraph(loop.operations)
+        refs = {}
+        if memory_refs:
+            opt = Optimizer(None, None, loop)
+
+
+        self.last_graph = DependencyGraph(loop.operations, refs)
         for i in range(len(self.last_graph.adjacent_list)):
             self.assert_independent(i,i)
         return self.last_graph
@@ -294,6 +300,9 @@
         """
         dep_graph = self.build_dependency(ops)
         self.assert_edges(dep_graph,
+                [ [1,2,4], [0,3], [0,3], [0,1,2,4], [0,3] ])
+        dep_graph = self.build_dependency(ops, memory_refs=True)
+        self.assert_edges(dep_graph,
                 [ [1,2,3,4], [0], [0,3], [0,2,4], [0,3] ])
 
 class TestLLtype(BaseTestDependencyGraph, LLtypeMixin):
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
@@ -703,7 +703,7 @@
         loop = self.parse_loop(ops)
         vopt = self.extend_pack_set(loop,1)
         self.debug_print_operations(loop)
-        assert len(vopt.vec_info.memory_refs) == 2
+        assert len(vopt.vec_info.memory_refs) == 4
         assert vopt.dependency_graph.independent(4,10)
         assert vopt.dependency_graph.independent(5,11)
         assert vopt.dependency_graph.independent(6,12)
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
@@ -2,7 +2,8 @@
 import py
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization
-from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from rpython.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
+        MemoryRef, IntegralMod)
 from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph
 from rpython.jit.metainterp.resoperation import rop
 from rpython.jit.metainterp.resume import Snapshot
@@ -183,7 +184,8 @@
         self.find_adjacent_memory_refs()
 
     def build_dependency_graph(self):
-        self.dependency_graph = DependencyGraph(self.loop.operations)
+        self.dependency_graph = \
+            DependencyGraph(self.loop.operations, self.vec_info.memory_refs)
 
     def find_adjacent_memory_refs(self):
         """ the pre pass already builds a hash of memory references and the
@@ -194,24 +196,6 @@
         all others are integers that are calculated in reverse direction"""
         loop = self.loop
         operations = loop.operations
-        integral_mod = IntegralMod(self)
-        for opidx,memref in self.vec_info.memory_refs.items():
-            integral_mod.reset()
-            while True:
-                for dep in self.dependency_graph.instr_dependencies(opidx):
-                    if dep.idx_from < opidx:
-                        op = operations[dep.idx_from]
-                        if op.result == memref.origin:
-                            opidx = dep.idx_from
-                            break
-                else:
-                    break # cannot go further, this might be the label, or a constant
-
-                integral_mod.inspect_operation(op)
-                if integral_mod.is_const_mod:
-                    integral_mod.update_memory_ref(memref)
-                else:
-                    break # an operation that is not tractable
 
         self.pack_set = PackSet(self.dependency_graph, operations)
         memory_refs = self.vec_info.memory_refs.items()
@@ -359,143 +343,6 @@
             return self.opidx == other.opidx and self.memref == other.memref
         return False
 
-class MemoryRef(object):
-    def __init__(self, array, origin, descr):
-        self.array = array
-        self.origin = origin
-        self.descr = descr
-        self.coefficient_mul = 1
-        self.coefficient_div = 1
-        self.constant = 0
-
-    def is_adjacent_to(self, other):
-        """ this is a symmetric relation """
-        match, off = self.calc_difference(other)
-        if match:
-            return off == 1 or off == -1
-        return False
-
-    def is_adjacent_after(self, other):
-        """ the asymetric relation to is_adjacent_to """
-        match, off = self.calc_difference(other)
-        if match:
-            return off == 1
-        return False
-
-    def __eq__(self, other):
-        match, off = self.calc_difference(other)
-        if match:
-            return off == 0
-        return False
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-
-    def calc_difference(self, other):
-        if self.array == other.array \
-            and self.origin == other.origin:
-            mycoeff = self.coefficient_mul // self.coefficient_div
-            othercoeff = other.coefficient_mul // other.coefficient_div
-            diff = other.constant - self.constant
-            return mycoeff == othercoeff, diff
-        return False, 0
-
-    def __repr__(self):
-        return 'MemoryRef(%s*(%s/%s)+%s)' % (self.origin, self.coefficient_mul,
-                                            self.coefficient_div, self.constant)
-
-class IntegralMod(object):
-    """ Calculates integral modifications on an integer object.
-    The operations must be provided in backwards direction and of one
-    variable only. Call reset() to reuse this object for other variables.
-    """
-
-    def __init__(self, optimizer):
-        self.optimizer = optimizer
-        self.reset()
-
-    def reset(self):
-        self.is_const_mod = False
-        self.coefficient_mul = 1
-        self.coefficient_div = 1
-        self.constant = 0
-        self.used_box = None
-
-    def _update_additive(self, i):
-        return (i * self.coefficient_mul) / self.coefficient_div
-
-    additive_func_source = """
-    def operation_{name}(self, op):
-        box_a0 = op.getarg(0)
-        box_a1 = op.getarg(1)
-        a0 = self.optimizer.getvalue(box_a0)
-        a1 = self.optimizer.getvalue(box_a1)
-        self.is_const_mod = True
-        if a0.is_constant() and a1.is_constant():
-            self.used_box = None
-            self.constant += self._update_additive(box_a0.getint() {op} \
-                                                      box_a1.getint())
-        elif a0.is_constant():
-            self.constant {op}= self._update_additive(box_a0.getint())
-            self.used_box = box_a1
-        elif a1.is_constant():
-            self.constant {op}= self._update_additive(box_a1.getint())
-            self.used_box = box_a0
-        else:
-            self.is_const_mod = False
-    """
-    exec py.code.Source(additive_func_source.format(name='INT_ADD', 
-                                                    op='+')).compile()
-    exec py.code.Source(additive_func_source.format(name='INT_SUB', 
-                                                    op='-')).compile()
-    del additive_func_source
-
-    multiplicative_func_source = """
-    def operation_{name}(self, op):
-        box_a0 = op.getarg(0)
-        box_a1 = op.getarg(1)
-        a0 = self.optimizer.getvalue(box_a0)
-        a1 = self.optimizer.getvalue(box_a1)
-        self.is_const_mod = True
-        if a0.is_constant() and a1.is_constant():
-            # here this factor becomes a constant, thus it is
-            # handled like any other additive operation
-            self.used_box = None
-            self.constant += self._update_additive(box_a0.getint() {cop} \
-                                                      box_a1.getint())
-        elif a0.is_constant():
-            self.coefficient_{tgt} {op}= box_a0.getint()
-            self.used_box = box_a1
-        elif a1.is_constant():
-            self.coefficient_{tgt} {op}= box_a1.getint()
-            self.used_box = box_a0
-        else:
-            self.is_const_mod = False
-    """
-    exec py.code.Source(multiplicative_func_source.format(name='INT_MUL', 
-                                                 op='*', tgt='mul',
-                                                 cop='*')).compile()
-    exec py.code.Source(multiplicative_func_source.format(name='INT_FLOORDIV',
-                                                 op='*', tgt='div',
-                                                 cop='/')).compile()
-    exec py.code.Source(multiplicative_func_source.format(name='UINT_FLOORDIV',
-                                                 op='*', tgt='div',
-                                                 cop='/')).compile()
-    del multiplicative_func_source
-    
-
-    def update_memory_ref(self, memref):
-        memref.constant = self.constant
-        memref.coefficient_mul = self.coefficient_mul
-        memref.coefficient_div = self.coefficient_div
-        memref.origin = self.used_box
-
-    def default_operation(self, operation):
-        pass
-integral_dispatch_opt = make_dispatcher_method(IntegralMod, 'operation_',
-        default=IntegralMod.default_operation)
-IntegralMod.inspect_operation = integral_dispatch_opt
 
 
 class LoopVectorizeInfo(object):
@@ -519,9 +366,18 @@
                or byte_count < self.smallest_type_bytes:
                 self.smallest_type_bytes = byte_count
     """
-    exec py.code.Source(array_access_source.format(name='RAW_LOAD')).compile()
-    exec py.code.Source(array_access_source.format(name='GETARRAYITEM_GC')).compile()
-    exec py.code.Source(array_access_source.format(name='GETARRAYITEM_RAW')).compile()
+    exec py.code.Source(array_access_source
+              .format(name='RAW_LOAD')).compile()
+    exec py.code.Source(array_access_source
+              .format(name='RAW_STORE')).compile()
+    exec py.code.Source(array_access_source
+              .format(name='GETARRAYITEM_GC')).compile()
+    exec py.code.Source(array_access_source
+              .format(name='SETARRAYITEM_GC')).compile()
+    exec py.code.Source(array_access_source
+              .format(name='GETARRAYITEM_RAW')).compile()
+    exec py.code.Source(array_access_source
+              .format(name='SETARRAYITEM_RAW')).compile()
     del array_access_source
 
     def default_operation(self, operation):


More information about the pypy-commit mailing list