[pypy-commit] pypy optresult: a minor rewrite + minor progress here, not sure about the correct API yet

fijal noreply at buildbot.pypy.org
Sat Nov 29 13:49:38 CET 2014


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: optresult
Changeset: r74758:4ce71001d704
Date: 2014-11-29 14:49 +0200
http://bitbucket.org/pypy/pypy/changeset/4ce71001d704/

Log:	a minor rewrite + minor progress here, not sure about the correct
	API yet

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
@@ -185,6 +185,9 @@
 class Const(AbstractValue):
     __slots__ = ()
 
+    is_source_op = True
+    source_op = None
+
     @staticmethod
     def _new(x):
         "NOT_RPYTHON"
diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py
--- a/rpython/jit/metainterp/optimizeopt/intbounds.py
+++ b/rpython/jit/metainterp/optimizeopt/intbounds.py
@@ -49,11 +49,10 @@
         assert not op.is_ovf()
         self.emit_operation(op)
 
-    def propagate_bounds_backward(self, box):
+    def propagate_bounds_backward(self, box, v):
         # FIXME: This takes care of the instruction where box is the reuslt
         #        but the bounds produced by all instructions where box is
         #        an argument might also be tighten
-        v = self.getvalue(box)
         b = v.intbound
         if b.has_lower and b.has_upper and b.lower == b.upper:
             v.make_constant(ConstInt(b.lower))
@@ -62,8 +61,9 @@
             dispatch_bounds_ops(self, box)
 
     def optimize_GUARD_TRUE(self, op):
+        v = self.getvalue(op.getarg(0))
         self.emit_operation(op)
-        self.propagate_bounds_backward(op.getarg(0))
+        self.propagate_bounds_backward(op.getarg(0), v)
 
     optimize_GUARD_FALSE = optimize_GUARD_TRUE
     optimize_GUARD_VALUE = optimize_GUARD_TRUE
@@ -237,25 +237,33 @@
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.add_bound(v2.intbound)
+        r = self.getvalue(op)
         if resbound.bounded():
             # Transform into INT_ADD.  The following guard will be killed
             # by optimize_GUARD_NO_OVERFLOW; if we see instead an
             # optimize_GUARD_OVERFLOW, then InvalidLoop.
-            op = self.optimizer.replace_op_with(op, rop.INT_ADD)
-        self.emit_operation(op) # emit the op
+            newop = op.copy_and_change(rop.INT_ADD)
+            r.box = newop
+        else:
+            newop = op
+        self.emit_operation(newop) # emit the op
         r = self.getvalue(op)
         r.intbound.intersect(resbound)
 
     def optimize_INT_SUB_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
+        r = self.getvalue(op)
         if v1 is v2:
             self.make_constant_int(op, 0)
             return
         resbound = v1.intbound.sub_bound(v2.intbound)
         if resbound.bounded():
-            op = self.optimizer.replace_op_with(op, rop.INT_SUB)
-        self.emit_operation(op) # emit the op
+            newop = op.copy_and_change(rop.INT_SUB)
+            r.box = newop
+        else:
+            newop = op
+        self.emit_operation(newop) # emit the op
         r = self.getvalue(op)
         r.intbound.intersect(resbound)
 
@@ -410,17 +418,17 @@
         v1 = self.getvalue(box1)
         v2 = self.getvalue(box2)
         if v1.intbound.make_lt(v2.intbound):
-            self.propagate_bounds_backward(box1)
+            self.propagate_bounds_backward(box1, v1)
         if v2.intbound.make_gt(v1.intbound):
-            self.propagate_bounds_backward(box2)
+            self.propagate_bounds_backward(box2, v2)
 
     def make_int_le(self, box1, box2):
         v1 = self.getvalue(box1)
         v2 = self.getvalue(box2)
         if v1.intbound.make_le(v2.intbound):
-            self.propagate_bounds_backward(box1)
+            self.propagate_bounds_backward(box1, v1)
         if v2.intbound.make_ge(v1.intbound):
-            self.propagate_bounds_backward(box2)
+            self.propagate_bounds_backward(box2, v2)
 
     def make_int_gt(self, box1, box2):
         self.make_int_lt(box2, box1)
@@ -467,9 +475,9 @@
                 v1 = self.getvalue(op.getarg(0))
                 v2 = self.getvalue(op.getarg(1))
                 if v1.intbound.intersect(v2.intbound):
-                    self.propagate_bounds_backward(op.getarg(0))
+                    self.propagate_bounds_backward(op.getarg(0), v1)
                 if v2.intbound.intersect(v1.intbound):
-                    self.propagate_bounds_backward(op.getarg(1))
+                    self.propagate_bounds_backward(op.getarg(1), v2)
 
     def propagate_bounds_INT_NE(self, op):
         r = self.getvalue(op)
@@ -489,7 +497,7 @@
                 v1 = self.getvalue(op.getarg(0))
                 if v1.intbound.known_ge(IntBound(0, 0)):
                     v1.intbound.make_gt(IntBound(0, 0))
-                    self.propagate_bounds_backward(op.getarg(0))
+                    self.propagate_bounds_backward(op.getarg(0), v1)
 
     def propagate_bounds_INT_IS_ZERO(self, op):
         r = self.getvalue(op)
@@ -501,7 +509,7 @@
                 # an assert, this is a clever way of expressing the same thing.
                 v1.intbound.make_ge(IntBound(0, 0))
                 v1.intbound.make_lt(IntBound(1, 1))
-                self.propagate_bounds_backward(op.getarg(0))
+                self.propagate_bounds_backward(op.getarg(0), v1)
 
     def propagate_bounds_INT_ADD(self, op):
         v1 = self.getvalue(op.getarg(0))
@@ -509,10 +517,10 @@
         r = self.getvalue(op)
         b = r.intbound.sub_bound(v2.intbound)
         if v1.intbound.intersect(b):
-            self.propagate_bounds_backward(op.getarg(0))
+            self.propagate_bounds_backward(op.getarg(0), v1)
         b = r.intbound.sub_bound(v1.intbound)
         if v2.intbound.intersect(b):
-            self.propagate_bounds_backward(op.getarg(1))
+            self.propagate_bounds_backward(op.getarg(1), v2)
 
     def propagate_bounds_INT_SUB(self, op):
         v1 = self.getvalue(op.getarg(0))
@@ -520,10 +528,10 @@
         r = self.getvalue(op)
         b = r.intbound.add_bound(v2.intbound)
         if v1.intbound.intersect(b):
-            self.propagate_bounds_backward(op.getarg(0))
+            self.propagate_bounds_backward(op.getarg(0), v1)
         b = r.intbound.sub_bound(v1.intbound).mul(-1)
         if v2.intbound.intersect(b):
-            self.propagate_bounds_backward(op.getarg(1))
+            self.propagate_bounds_backward(op.getarg(1), v2)
 
     def propagate_bounds_INT_MUL(self, op):
         v1 = self.getvalue(op.getarg(0))
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -64,15 +64,6 @@
             self.make_constant(box)
         # invariant: box is a Const if and only if level == LEVEL_CONSTANT
 
-    def copy_attributes_from(self, other):
-        assert other.__class__ is OptValue
-        self.level = other.level
-        self.known_class = other.known_class
-        self.intbound = other.intbound
-        self.lenbound = other.lenbound
-        self.box = other.box
-        self.last_guard = other.last_guard
-
     def make_len_gt(self, mode, descr, val):
         if self.lenbound:
             assert self.lenbound.mode == mode
@@ -454,6 +445,9 @@
 
     @specialize.argtype(0)
     def getvalue(self, box):
+        while box.source_op is not None:
+            box = box.source_op
+        assert box.is_source_op
         box = self.getinterned(box)
         try:
             value = self.values[box]
@@ -487,19 +481,13 @@
     def clear_newoperations(self):
         self._newoperations = []
 
-    def make_equal_to(self, box, newvalue):
-        if box in self.values:
-            v = self.getvalue(box)
-            v.copy_attributes_from(newvalue)
-        else:
-            self.values[box] = newvalue
-
-    def replace_op_with(self, oldop, newopnum, args=None):
-        newop = oldop._copy_and_change(newopnum, args=args)
-        v = self.getvalue(oldop)
-        v.box = newop
-        self.values[newop] = v
-        return newop
+    def make_equal_to(self, box, value, replace=False):
+        assert isinstance(value, OptValue)
+        assert replace or box not in self.values
+        while box.source_op is not None:
+            box = box.source_op
+        assert box.is_source_op
+        self.values[box] = value
 
     def make_constant(self, box, constbox):
         try:
@@ -574,6 +562,10 @@
     @specialize.argtype(0)
     def _emit_operation(self, op):
         assert not op.is_call_pure()
+        if op.getopnum() == rop.GUARD_VALUE:
+            val = self.getvalue(op.getarg(0))
+        else:
+            val = None
         for i in range(op.numargs()):
             arg = op.getarg(i)
             try:
@@ -593,7 +585,7 @@
                 del self.replaces_guard[op]
                 return
             else:
-                op = self.store_final_boxes_in_guard(op, pendingfields)
+                op = self.store_final_boxes_in_guard(op, pendingfields, val)
         elif op.can_raise():
             self.exception_might_have_happened = True
         self._newoperations.append(op)
@@ -609,7 +601,7 @@
         else:
             assert False
 
-    def store_final_boxes_in_guard(self, op, pendingfields):
+    def store_final_boxes_in_guard(self, op, pendingfields, val):
         assert pendingfields is not None
         descr = op.getdescr()
         assert isinstance(descr, compile.ResumeGuardDescr)
@@ -624,7 +616,7 @@
         descr.store_final_boxes(op, newboxes, self.metainterp_sd)
         #
         if op.getopnum() == rop.GUARD_VALUE:
-            if self.getvalue(op.getarg(0)) in self.bool_boxes:
+            if val in self.bool_boxes:
                 # Hack: turn guard_value(bool) into guard_true/guard_false.
                 # This is done after the operation is emitted to let
                 # store_final_boxes_in_guard set the guard_opnum field of the
diff --git a/rpython/jit/metainterp/optimizeopt/pure.py b/rpython/jit/metainterp/optimizeopt/pure.py
--- a/rpython/jit/metainterp/optimizeopt/pure.py
+++ b/rpython/jit/metainterp/optimizeopt/pure.py
@@ -42,7 +42,7 @@
                                                 op.getarglist(), op.getdescr())
             oldop = self.pure_operations.get(args, None)
             if oldop is not None and oldop.getdescr() is op.getdescr():
-                self.optimizer.make_equal_to(op, self.getvalue(oldop))
+                self.optimizer.make_equal_to(op, self.getvalue(oldop), True)
                 return
             else:
                 self.pure_operations[args] = op
@@ -84,6 +84,7 @@
         args = op.getarglist()
         opnum = OpHelpers.call_for_descr(op.getdescr())
         newop = ResOperation(opnum, args, op.getdescr())
+        newop.source_op = op
         self.getvalue(op).box = newop
         self.emit_operation(newop)
     optimize_CALL_PURE_R = optimize_CALL_PURE_I
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -220,8 +220,8 @@
                     self.make_equal_to(op, v2)
                     return
                 elif v1.box.getfloatstorage() == -1.0:
-                    newop = self.optimizer.replace_op_with(op, rop.FLOAT_NEG,
-                                                           args=[rhs])
+                    newop = op.copy_and_change(rop.FLOAT_NEG, args=[rhs])
+                    self.getvalue(op).box = newop
                     self.emit_operation(newop)
                     return
         self.emit_operation(op)
@@ -233,6 +233,7 @@
         v2 = self.getvalue(arg2)
 
         # replace "x / const" by "x * (1/const)" if possible
+        newop = op
         if v2.is_constant():
             divisor = v2.box.getfloatstorage()
             fraction = math.frexp(divisor)[0]
@@ -243,9 +244,9 @@
                 rfraction = math.frexp(reciprocal)[0]
                 if rfraction == 0.5 or rfraction == -0.5:
                     c = ConstFloat(longlong.getfloatstorage(reciprocal))
-                    op = self.optimizer.replace_op_with(op, rop.FLOAT_MUL,
-                                                        args=[arg1, c])
-        self.emit_operation(op)
+                    newop = op.copy_and_change(rop.FLOAT_MUL, args=[arg1, c])
+                    self.getvalue(op).box = newop
+        self.emit_operation(newop)
 
     def optimize_FLOAT_NEG(self, op):
         v1 = op.getarg(0)
@@ -291,6 +292,7 @@
 
     def optimize_GUARD_VALUE(self, op):
         value = self.getvalue(op.getarg(0))
+        opv = self.getvalue(op)
         if value.is_virtual():
             arg = value.get_constant_class(self.optimizer.cpu)
             if arg:
@@ -316,10 +318,8 @@
                     r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
                     raise InvalidLoop('A GUARD_VALUE (%s) was proven to always fail' % r)
             arglist = [old_guard_op.getarg(0), op.getarg(1)]
-            op = self.optimizer.replace_op_with(old_guard_op,
-                                                rop.GUARD_VALUE,
-                                                args=arglist)
-            self.getvalue(old_guard_op).box = op
+            op = old_guard_op.copy_and_change(rop.GUARD_VALUE, args=arglist)
+            opv.box = op
             self.optimizer.replaces_guard[op] = old_guard_op
             # hack hack hack.  Change the guard_opnum on
             # new_guard_op.getdescr() so that when resuming,
@@ -351,6 +351,7 @@
         value.make_constant_class(expectedclassbox, None)
 
     def optimize_GUARD_CLASS(self, op):
+        opv = self.getvalue(op)
         value = self.getvalue(op.getarg(0))
         expectedclassbox = op.getarg(1)
         assert isinstance(expectedclassbox, Const)
@@ -369,9 +370,8 @@
                 # it was a guard_nonnull, which we replace with a
                 # guard_nonnull_class.
                 args = [old_guard_op.getarg(0), op.getarg(1)]
-                op = self.optimizer.replace_op_with(old_guard_op,
-                                                    rop.GUARD_NONNULL_CLASS,
-                                                    args)
+                op = old_guard_op.copy_and_change(rop.GUARD_NONNULL_CLASS, args)
+                opv.box = op
                 self.optimizer.replaces_guard[op] = old_guard_op
                 # hack hack hack.  Change the guard_opnum on
                 # new_guard_op.getdescr() so that when resuming,
@@ -406,10 +406,10 @@
         # there is no reason to have a separate operation for this
         self.loop_invariant_producer[key] = op
         opnum = OpHelpers.call_for_descr(op.getdescr())
-        newop = self.optimizer.replace_op_with(op, opnum)
+        newop = op.copy_and_change(opnum)
+        resvalue = self.optimizer.getvalue(op)
+        resvalue.box = newop
         self.emit_operation(newop)
-        resvalue = self.getvalue(op)
-        resvalue.box = newop
         self.loop_invariant_results[key] = resvalue
     optimize_CALL_LOOPINVARIANT_R = optimize_CALL_LOOPINVARIANT_I
     optimize_CALL_LOOPINVARIANT_F = optimize_CALL_LOOPINVARIANT_I
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -27,7 +27,7 @@
     snapshot0 = resume.Snapshot(None, [b0])
     fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1])
     #
-    opt.store_final_boxes_in_guard(op, [])
+    opt.store_final_boxes_in_guard(op, [], None)
     if op.getfailargs() == [b0, b1]:
         assert list(fdescr.rd_numb.nums)      == [tag(1, TAGBOX)]
         assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)]
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -39,6 +39,9 @@
     boolreflex = -1
     boolinverse = -1
 
+    is_source_op = False
+    source_op = None
+
     _attrs_ = ()
 
     def getopnum(self):
@@ -87,7 +90,7 @@
     # common methods
     # --------------
 
-    def _copy_and_change(self, opnum, args=None, descr=None):
+    def copy_and_change(self, opnum, args=None, descr=None):
         "shallow copy: the returned operation is meant to be used in place of self"
         if args is None:
             args = self.getarglist()
@@ -96,6 +99,7 @@
         newop = ResOperation(opnum, args, descr)
         if self.type != 'v':
             newop.copy_value_from(self)
+        newop.source_op = self
         return newop
 
     @specialize.argtype(1)
@@ -279,8 +283,8 @@
     def setfailargs(self, fail_args):
         self._fail_args = fail_args
 
-    def _copy_and_change(self, opnum, args=None, descr=None):
-        newop = AbstractResOp._copy_and_change(self, opnum, args, descr)
+    def copy_and_change(self, opnum, args=None, descr=None):
+        newop = AbstractResOp.copy_and_change(self, opnum, args, descr)
         newop.setfailargs(self.getfailargs())
         return newop
 
@@ -359,7 +363,10 @@
     def nonnull(self):
         return bool(self._resref)
 
-class AbstractInputArg(AbstractValue):    
+class AbstractInputArg(AbstractValue):
+    is_source_op = True
+    source_op = None
+    
     def repr(self, memo):
         try:
             return memo[self]
diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py
--- a/rpython/jit/tool/oparser.py
+++ b/rpython/jit/tool/oparser.py
@@ -17,6 +17,7 @@
     OPNUM = -123
 
     type = 'i'
+    is_source_op = True
 
     def getopnum(self):
         return self.OPNUM
@@ -32,6 +33,7 @@
 class FORCE_SPILL(UnaryOp, PlainResOp):
 
     OPNUM = -124
+    is_source_op = True
 
     def getopnum(self):
         return self.OPNUM
@@ -277,7 +279,9 @@
             assert descr is None
             return op
         else:
-            return ResOperation(opnum, args, descr)
+            res = ResOperation(opnum, args, descr)
+            res.is_source_op = True
+            return res
 
     def parse_result_op(self, line):
         res, op = line.split("=", 1)


More information about the pypy-commit mailing list