[pypy-commit] pypy optresult: merge recent-ops

fijal noreply at buildbot.pypy.org
Fri Mar 6 16:22:34 CET 2015


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: optresult
Changeset: r76255:456f069a2ff4
Date: 2015-03-06 17:22 +0200
http://bitbucket.org/pypy/pypy/changeset/456f069a2ff4/

Log:	merge recent-ops

diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -73,7 +73,6 @@
     assume_immutable_completions = False
     use_brackets = False
     sort_in_column = True
-    tab_insert_spaces_if_stem_is_empty = False
 
     def error(self, msg="none"):
         pass    # don't show error messages by default
@@ -87,7 +86,7 @@
         return ''.join(b[p+1:self.pos])
 
     def get_completions(self, stem):
-        if len(stem) == 0 and self.tab_insert_spaces_if_stem_is_empty:
+        if len(stem) == 0 and self.more_lines is not None:
             b = self.buffer
             p = self.pos
             while p > 0 and b[p - 1] != '\n':
@@ -141,12 +140,16 @@
 
     def collect_keymap(self):
         return super(ReadlineAlikeReader, self).collect_keymap() + (
-            (r'\n', 'maybe-accept'),)
+            (r'\n', 'maybe-accept'),
+            (r'\<backspace>', 'backspace-dedent'),
+            )
 
     def __init__(self, console):
         super(ReadlineAlikeReader, self).__init__(console)
         self.commands['maybe_accept'] = maybe_accept
         self.commands['maybe-accept'] = maybe_accept
+        self.commands['backspace_dedent'] = backspace_dedent
+        self.commands['backspace-dedent'] = backspace_dedent
 
     def after_command(self, cmd):
         super(ReadlineAlikeReader, self).after_command(cmd)
@@ -164,6 +167,28 @@
                 if self.pos > len(self.buffer):
                     self.pos = len(self.buffer)
 
+def _get_this_line_indent(buffer, pos):
+    indent = 0
+    while pos > 0 and buffer[pos - 1] in " \t":
+        indent += 1
+        pos -= 1
+    if pos > 0 and buffer[pos - 1] == "\n":
+        return indent
+    return 0
+
+def _get_previous_line_indent(buffer, pos):
+    prevlinestart = pos
+    while prevlinestart > 0 and buffer[prevlinestart - 1] != "\n":
+        prevlinestart -= 1
+    prevlinetext = prevlinestart
+    while prevlinetext < pos and buffer[prevlinetext] in " \t":
+        prevlinetext += 1
+    if prevlinetext == pos:
+        indent = None
+    else:
+        indent = prevlinetext - prevlinestart
+    return prevlinestart, indent
+
 class maybe_accept(commands.Command):
     def do(self):
         r = self.reader
@@ -172,13 +197,39 @@
         # if there are already several lines and the cursor
         # is not on the last one, always insert a new \n.
         text = r.get_unicode()
-        if "\n" in r.buffer[r.pos:]:
+        if ("\n" in r.buffer[r.pos:] or
+            (r.more_lines is not None and r.more_lines(text))):
+            #
+            # auto-indent the next line like the previous line
+            prevlinestart, indent = _get_previous_line_indent(r.buffer, r.pos)
             r.insert("\n")
-        elif r.more_lines is not None and r.more_lines(text):
-            r.insert("\n")
+            if indent:
+                for i in range(prevlinestart, prevlinestart + indent):
+                    r.insert(r.buffer[i])
         else:
             self.finish = 1
 
+class backspace_dedent(commands.Command):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        if r.pos > 0:
+            repeat = 1
+            if b[r.pos - 1] != "\n":
+                indent = _get_this_line_indent(b, r.pos)
+                if indent > 0:
+                    ls = r.pos - indent
+                    while ls > 0:
+                        ls, pi = _get_previous_line_indent(b, ls - 1)
+                        if pi is not None and pi < indent:
+                            repeat = indent - pi
+                            break
+            r.pos -= repeat
+            del b[r.pos:r.pos + repeat]
+            r.dirty = 1
+        else:
+            self.reader.error("can't backspace at start")
+
 # ____________________________________________________________
 
 class _ReadlineWrapper(object):
@@ -212,15 +263,14 @@
         boolean value is true.
         """
         reader = self.get_reader()
-        saved = reader.more_lines, reader.tab_insert_spaces_if_stem_is_empty
+        saved = reader.more_lines
         try:
             reader.more_lines = more_lines
             reader.ps1 = reader.ps2 = ps1
             reader.ps3 = reader.ps4 = ps2
-            reader.tab_insert_spaces_if_stem_is_empty = True
             return reader.readline(returns_unicode=returns_unicode)
         finally:
-            reader.more_lines, reader.tab_insert_spaces_if_stem_is_empty = saved
+            reader.more_lines = saved
 
     def parse_and_bind(self, string):
         pass  # XXX we don't support parsing GNU-readline-style init files
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
@@ -211,15 +211,15 @@
             # Else, synthesize the non overflowing op for optimize_default to
             # reuse, as well as the reverse op
             elif opnum == rop.INT_ADD_OVF:
-                self.pure(rop.INT_ADD, args[:], result)
+                #self.pure(rop.INT_ADD, args[:], result)
                 self.pure(rop.INT_SUB, [result, args[1]], args[0])
                 self.pure(rop.INT_SUB, [result, args[0]], args[1])
             elif opnum == rop.INT_SUB_OVF:
-                self.pure(rop.INT_SUB, args[:], result)
+                #self.pure(rop.INT_SUB, args[:], result)
                 self.pure(rop.INT_ADD, [result, args[1]], args[0])
                 self.pure(rop.INT_SUB, [args[0], result], args[1])
-            elif opnum == rop.INT_MUL_OVF:
-                self.pure(rop.INT_MUL, args[:], result)
+            #elif opnum == rop.INT_MUL_OVF:
+            #    self.pure(rop.INT_MUL, args[:], result)
         self.emit_operation(op)
 
     def optimize_GUARD_OVERFLOW(self, op):
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
@@ -323,6 +323,9 @@
     def replace_op_with(self, op, newopnum, args=None, descr=None):
         return self.optimizer.replace_op_with(op, newopnum, args, descr)
 
+    def get_box_replacement(self, box):
+        return self.optimizer.get_box_replacement(box)
+
     def make_constant(self, box, constbox):
         return self.optimizer.make_constant(box, constbox)
 
@@ -399,6 +402,7 @@
 class Optimizer(Optimization):
 
     exporting_state = False
+    emitting_dissabled = False
 
     def __init__(self, metainterp_sd, jitdriver_sd, loop, optimizations=None):
         self.metainterp_sd = metainterp_sd
@@ -609,7 +613,7 @@
         if clear:
             self.clear_newoperations()
         for op in self.loop.operations:
-            self._last_emitted_op = None
+            self._really_emitted_operation = None
             self.first_optimization.propagate_forward(op)
         self.loop.operations = self.get_newoperations()
         self.loop.quasi_immutable_deps = self.quasi_immutable_deps
@@ -651,9 +655,12 @@
                 op = self.store_final_boxes_in_guard(guard_op, pendingfields)
         elif op.can_raise():
             self.exception_might_have_happened = True
-        self._last_emitted_op = op
+        self._really_emitted_operation = op
         self._newoperations.append(op)
 
+    def getlastop(self):
+        return self._really_emitted_operation
+
     def replace_guard_op(self, old_op_pos, new_op):
         old_op = self._newoperations[old_op_pos]
         assert old_op.is_guard()
@@ -705,16 +712,6 @@
                 descr.make_a_counter_per_value(op)
         return op
 
-    def make_args_key(self, opnum, arglist, descr):
-        n = len(arglist)
-        args = [None] * (n + 2)
-        for i in range(n):
-            arg = self.get_box_replacement(arglist[i])
-            args[i] = arg
-        args[n] = ConstInt(opnum)
-        args[n + 1] = descr
-        return args
-
     def optimize_default(self, op):
         self.emit_operation(op)
 
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
@@ -1,13 +1,59 @@
 from rpython.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
-from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers
-from rpython.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
-    args_dict)
+from rpython.jit.metainterp.resoperation import rop, ResOperation
+from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
+
+
+class RecentPureOps(object):
+    REMEMBER_LIMIT = 16
+
+    def __init__(self):
+        self.lst = [None] * self.REMEMBER_LIMIT
+        self.next_index = 0
+
+    def add(self, op):
+        next_index = self.next_index
+        self.next_index = (next_index + 1) % self.REMEMBER_LIMIT
+        self.lst[next_index] = op
+
+    def lookup1(self, box0, descr):
+        for i in range(self.REMEMBER_LIMIT):
+            op = self.lst[i]
+            if op is None:
+                break
+            if op.getarg(0).same_box(box0) and op.getdescr() is descr:
+                return op
+        return None
+
+    def lookup2(self, box0, box1, descr):
+        for i in range(self.REMEMBER_LIMIT):
+            op = self.lst[i]
+            if op is None:
+                break
+            if (op.getarg(0).same_box(box0) and op.getarg(1).same_box(box1)
+                and op.getdescr() is descr):
+                return op
+        return None
+
+    def lookup(self, optimizer, op):
+        numargs = op.numargs()
+        if numargs == 1:
+            return self.lookup1(optimizer.get_box_replacement(op.getarg(0)),
+                                op.getdescr())
+        elif numargs == 2:
+            return self.lookup2(optimizer.get_box_replacement(op.getarg(0)),
+                                optimizer.get_box_replacement(op.getarg(1)),
+                                op.getdescr())
+        else:
+            assert False
+
 
 class OptPure(Optimization):
     def __init__(self):
         self.postponed_op = None
-        self.pure_operations = args_dict()
+        self._pure_operations = [None] * (rop._ALWAYS_PURE_LAST -
+                                          rop._ALWAYS_PURE_FIRST)
         self.call_pure_positions = []
+        self.extra_call_pure = []
 
     def propagate_forward(self, op):
         dispatch_opt(self, op)
@@ -25,7 +71,7 @@
         else:
             nextop = None
 
-        args = None
+        save = False
         if canfold:
             for i in range(op.numargs()):
                 if self.get_constant_box(op.getarg(i)) is None:
@@ -39,22 +85,34 @@
                 return
 
             # did we do the exact same operation already?
-            if 0:
-                args = self.optimizer.make_args_key(op.getopnum(),
-                                                    op.getarglist(), op.getdescr())
-                oldval = self.pure_operations.get(args, None)
-                if oldval is not None:
-                    self.optimizer.make_equal_to(op, oldval)
-                    return
+            recentops = self.getrecentops(op.getopnum())
+            save = True
+            oldop = recentops.lookup(self.optimizer, op)
+            if oldop is not None:
+                self.optimizer.make_equal_to(op, oldop)
+                return
 
         # otherwise, the operation remains
         self.emit_operation(op)
         if op.returns_bool_result():
             self.getintbound(op).make_bool()
+        if save:
+            realop = self.get_box_replacement(op)
+            recentops = self.getrecentops(realop.getopnum())
+            recentops.add(realop)
         if nextop:
             self.emit_operation(nextop)
-        #if args is not None:
-        #    self.pure_operations[args] = self.getvalue(op)
+
+    def getrecentops(self, opnum):
+        if rop._OVF_FIRST <= opnum <= rop._OVF_LAST:
+            opnum = opnum - rop._OVF_FIRST
+        else:
+            opnum = opnum - rop._ALWAYS_PURE_FIRST
+        assert 0 <= opnum < len(self._pure_operations)
+        recentops = self._pure_operations[opnum]
+        if recentops is None:
+            self._pure_operations[opnum] = recentops = RecentPureOps()
+        return recentops
 
     def optimize_CALL_PURE_I(self, op):
         # Step 1: check if all arguments are constant
@@ -67,28 +125,45 @@
 
         # Step 2: check if all arguments are the same as a previous
         # CALL_PURE.
-        args = self.optimizer.make_args_key(op.getopnum(), op.getarglist(),
-                                            op.getdescr())
-        oldval = self.pure_operations.get(args, None)
-        if oldval is not None:
-            # this removes a CALL_PURE that has the same (non-constant)
-            # arguments as a previous CALL_PURE.
-            self.make_equal_to(op, oldval)
-            self.last_emitted_operation = REMOVED
-            return
-        else:
-            self.pure_operations[args] = self.getvalue(op)
+        for pos in self.call_pure_positions:
+            old_op = self.optimizer._newoperations[pos]
+            if self.optimize_call_pure(op, old_op):
+                return
+        for old_op in self.extra_call_pure:
+            if self.optimize_call_pure(op, old_op):
+                return
 
         # replace CALL_PURE with just CALL
         args = op.getarglist()
         opnum = OpHelpers.call_for_descr(op.getdescr())
         newop = self.optimizer.replace_op_with(op, opnum)
         self.emit_operation(newop)
-        self.call_pure_positions.append(len(self.optimizer._newoperations) - 1)
+        if self.optimizer.emitting_dissabled:
+            self.extra_call_pure.append(op) # XXX
+        else:
+            self.call_pure_positions.append(len(self.optimizer._newoperations)
+                                            - 1)
     optimize_CALL_PURE_R = optimize_CALL_PURE_I
     optimize_CALL_PURE_F = optimize_CALL_PURE_I
     optimize_CALL_PURE_N = optimize_CALL_PURE_I
 
+    def optimize_call_pure(self, op, old_op):
+        if (op.numargs() != old_op.numargs() or
+            op.getdescr() is not old_op.getdescr()):
+            return False
+        for i, box in enumerate(old_op.getarglist()):
+            if not self.get_box_replacement(op.getarg(i)).same_box(box):
+                break
+        else:
+            # all identical
+            # this removes a CALL_PURE that has the same (non-constant)
+            # arguments as a previous CALL_PURE.
+            oldvalue = self.getvalue(old_op.result)
+            self.make_equal_to(op.result, oldvalue)
+            self.last_emitted_operation = REMOVED
+            return True
+        return False
+
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
             # it was a CALL_PURE that was killed; so we also kill the
@@ -102,18 +177,18 @@
     def setup(self):
         self.optimizer.optpure = self
 
-    def pure(self, opnum, args, result):
-        return # XXX
-        key = self.optimizer.make_args_key(opnum, args, None)
-        if key not in self.pure_operations:
-            self.pure_operations[key] = self.getvalue(result)
+    def pure(self, opnum, args, op):
+        op = self.get_box_replacement(op)
+        recentops = self.getrecentops(opnum)
+        recentops.add(op)
 
     def has_pure_result(self, opnum, args, descr):
-        key = self.optimizer.make_args_key(opnum, args, descr)
-        return self.pure_operations.get(key, None) is not None
+        return False
+    # XXX
 
-    def get_pure_result(self, key):
-        return self.pure_operations.get(key, None)
+    def get_pure_result(self, op):
+        recentops = self.getrecentops(op.getopnum())
+        return recentops.lookup(self.optimizer, op)
 
     def produce_potential_short_preamble_ops(self, sb):
         ops = sb.optimizer._newoperations
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
@@ -27,16 +27,15 @@
 
     def propagate_forward(self, op):
         if op.boolinverse != -1 or op.boolreflex != -1:
-            args = self.optimizer.make_args_key(op.getopnum(),
-                                                op.getarglist(), op.getdescr())
-            if self.find_rewritable_bool(op, args):
+            if self.find_rewritable_bool(op):
                 return
 
         dispatch_opt(self, op)
 
     def try_boolinvers(self, op, targs):
-        value = self.get_pure_result(targs)
-        if value is not None:
+        oldop = self.get_pure_result(targs)
+        if oldop is not None:
+            value = self.getvalue(oldop.result)
             if value.is_constant():
                 if value.box.same_constant(CONST_1):
                     self.make_constant(op, CONST_0)
@@ -48,30 +47,30 @@
         return False
 
 
-    def find_rewritable_bool(self, op, args):
+    def find_rewritable_bool(self, op):
         oldopnum = op.boolinverse
+        arg0 = op.getarg(0)
+        arg1 = op.getarg(1)
         if oldopnum != -1:
-            targs = self.optimizer.make_args_key(oldopnum, [args[0], args[1]],
-                                                 None)
-            if self.try_boolinvers(op, targs):
+            top = ResOperation(oldopnum, [arg0, arg1], None)
+            if self.try_boolinvers(op, top):
                 return True
 
         oldopnum = op.boolreflex # FIXME: add INT_ADD, INT_MUL
         if oldopnum != -1:
-            targs = self.optimizer.make_args_key(oldopnum, [args[1], args[0]],
-                                                 None)
-            oldval = self.get_pure_result(targs)
-            if oldval is not None:
-                self.make_equal_to(op, oldval)
+            top = ResOperation(oldopnum, [arg1, arg0], None)
+            oldop = self.get_pure_result(top)
+            if oldop is not None:
+                self.optimizer.make_equal_to(op.result,
+                                             self.getvalue(oldop.result), True)
                 return True
 
         if op.boolreflex == -1:
             return False
         oldopnum = opclasses[op.boolreflex].boolinverse
         if oldopnum != -1:
-            targs = self.optimizer.make_args_key(oldopnum, [args[1], args[0]],
-                                                 None)
-            if self.try_boolinvers(op, targs):
+            top = ResOperation(oldopnum, [arg1, arg0], None)
+            if self.try_boolinvers(op, top):
                 return True
 
         return False
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -4759,6 +4759,7 @@
         self.optimize_loop(ops, expected)
 
     def test_complains_getfieldpure_setfield(self):
+        py.test.skip("disabled for now")
         from rpython.jit.metainterp.optimizeopt.heap import BogusPureField
         ops = """
         [p3]
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
@@ -779,7 +779,7 @@
     '_CANRAISE_LAST', # ----- end of can_raise operations -----
 
     '_OVF_FIRST', # ----- start of is_ovf operations -----
-    'INT_ADD_OVF/2/i',
+    'INT_ADD_OVF/2/i', # note that the orded has to match INT_ADD order
     'INT_SUB_OVF/2/i',
     'INT_MUL_OVF/2/i',
     '_OVF_LAST', # ----- end of is_ovf operations -----


More information about the pypy-commit mailing list