[pypy-commit] pypy SpecialisedTuples: hg merge default

arigo noreply at buildbot.pypy.org
Fri Dec 9 12:01:53 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: SpecialisedTuples
Changeset: r50322:4efbd07c3e55
Date: 2011-12-09 12:01 +0100
http://bitbucket.org/pypy/pypy/changeset/4efbd07c3e55/

Log:	hg merge default

diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -23,9 +23,12 @@
         return self.frame_bindings.get(box, None)
 
     def loc(self, box):
-        res = self.get(box)
-        if res is not None:
-            return res
+        try:
+            return self.frame_bindings[box]
+        except KeyError:
+            return self.get_new_loc(box)
+
+    def get_new_loc(self, box):
         size = self.frame_size(box.type)
         self.frame_depth += ((-self.frame_depth) & (size-1))
         # ^^^ frame_depth is rounded up to a multiple of 'size', assuming
@@ -67,8 +70,17 @@
         self.position = -1
         self.frame_manager = frame_manager
         self.assembler = assembler
+        self.hint_frame_locations = {}     # {Box: StackLoc}
+        self.freed_frame_locations = {}    # {StackLoc: None}
+
+    def is_still_alive(self, v):
+        # Check if 'v' is alive at the current position.
+        # Return False if the last usage is strictly before.
+        return self.longevity[v][1] >= self.position
 
     def stays_alive(self, v):
+        # Check if 'v' stays alive after the current position.
+        # Return False if the last usage is before or at position.
         return self.longevity[v][1] > self.position
 
     def next_instruction(self, incr=1):
@@ -84,11 +96,16 @@
             point for all variables that might be in registers.
         """
         self._check_type(v)
-        if isinstance(v, Const) or v not in self.reg_bindings:
+        if isinstance(v, Const):
             return
         if v not in self.longevity or self.longevity[v][1] <= self.position:
-            self.free_regs.append(self.reg_bindings[v])
-            del self.reg_bindings[v]
+            if v in self.reg_bindings:
+                self.free_regs.append(self.reg_bindings[v])
+                del self.reg_bindings[v]
+            if self.frame_manager is not None:
+                if v in self.frame_manager.frame_bindings:
+                    loc = self.frame_manager.frame_bindings[v]
+                    self.freed_frame_locations[loc] = None
 
     def possibly_free_vars(self, vars):
         """ Same as 'possibly_free_var', but for all v in vars.
@@ -160,6 +177,23 @@
                 self.reg_bindings[v] = loc
                 return loc
 
+    def _frame_loc(self, v):
+        # first check if it's already in the frame_manager
+        try:
+            return self.frame_manager.frame_bindings[v]
+        except KeyError:
+            pass
+        # check if we have a hint for this box
+        if v in self.hint_frame_locations:
+            # if we do, check that the hinted location is known to be free
+            loc = self.hint_frame_locations[v]
+            if loc in self.freed_frame_locations:
+                del self.freed_frame_locations[loc]
+                self.frame_manager.frame_bindings[v] = loc
+                return loc
+        # no valid hint.  make up a new free location
+        return self.frame_manager.get_new_loc(v)
+
     def _spill_var(self, v, forbidden_vars, selected_reg,
                    need_lower_byte=False):
         v_to_spill = self._pick_variable_to_spill(v, forbidden_vars,
@@ -167,7 +201,7 @@
         loc = self.reg_bindings[v_to_spill]
         del self.reg_bindings[v_to_spill]
         if self.frame_manager.get(v_to_spill) is None:
-            newloc = self.frame_manager.loc(v_to_spill)
+            newloc = self._frame_loc(v_to_spill)
             self.assembler.regalloc_mov(loc, newloc)
         return loc
 
@@ -244,7 +278,7 @@
         except KeyError:
             if box in self.bindings_to_frame_reg:
                 return self.frame_reg
-            return self.frame_manager.loc(box)
+            return self._frame_loc(box)
 
     def return_constant(self, v, forbidden_vars=[], selected_reg=None):
         """ Return the location of the constant v.  If 'selected_reg' is
@@ -292,7 +326,7 @@
             self.reg_bindings[v] = loc
             self.assembler.regalloc_mov(prev_loc, loc)
         else:
-            loc = self.frame_manager.loc(v)
+            loc = self._frame_loc(v)
             self.assembler.regalloc_mov(prev_loc, loc)
 
     def force_result_in_reg(self, result_v, v, forbidden_vars=[]):
@@ -311,7 +345,7 @@
             self.reg_bindings[result_v] = loc
             return loc
         if v not in self.reg_bindings:
-            prev_loc = self.frame_manager.loc(v)
+            prev_loc = self._frame_loc(v)
             loc = self.force_allocate_reg(v, forbidden_vars)
             self.assembler.regalloc_mov(prev_loc, loc)
         assert v in self.reg_bindings
@@ -331,7 +365,7 @@
     def _sync_var(self, v):
         if not self.frame_manager.get(v):
             reg = self.reg_bindings[v]
-            to = self.frame_manager.loc(v)
+            to = self._frame_loc(v)
             self.assembler.regalloc_mov(reg, to)
         # otherwise it's clean
 
diff --git a/pypy/jit/backend/llsupport/test/test_regalloc.py b/pypy/jit/backend/llsupport/test/test_regalloc.py
--- a/pypy/jit/backend/llsupport/test/test_regalloc.py
+++ b/pypy/jit/backend/llsupport/test/test_regalloc.py
@@ -348,3 +348,50 @@
         spilled2 = rm.force_allocate_reg(b5)
         assert spilled2 is loc
         rm._check_invariants()
+
+
+    def test_hint_frame_locations_1(self):
+        b0, b1 = newboxes(0, 1)
+        longevity = {b0: (0, 1), b1: (0, 1)}
+        fm = TFrameManager()
+        asm = MockAsm()
+        rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
+        rm.hint_frame_locations[b0] = "some_stack_loc"
+        rm.freed_frame_locations["some_stack_loc"] = None
+        rm.force_allocate_reg(b0)
+        rm.force_allocate_reg(b1)
+        rm.force_spill_var(b0)
+        rm.force_spill_var(b1)
+        assert rm.loc(b0) == "some_stack_loc"
+        assert isinstance(rm.loc(b1), FakeFramePos)
+        rm._check_invariants()
+
+    def test_hint_frame_locations_2(self):
+        b0, b1, b2 = newboxes(0, 1, 2)
+        longevity = {b0: (0, 1), b1: (0, 2), b2: (0, 2)}
+        fm = TFrameManager()
+        asm = MockAsm()
+        rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
+        rm.force_allocate_reg(b0)
+        rm.force_allocate_reg(b1)
+        rm.force_allocate_reg(b2)
+        rm.force_spill_var(b0)
+        loc = rm.loc(b0)
+        assert isinstance(loc, FakeFramePos)
+        rm.position = 1
+        assert loc not in rm.freed_frame_locations
+        rm.possibly_free_var(b0)
+        assert loc in rm.freed_frame_locations
+        #
+        rm.hint_frame_locations[b1] = loc
+        rm.force_spill_var(b1)
+        loc1 = rm.loc(b1)
+        assert loc1 is loc
+        assert rm.freed_frame_locations == {}
+        #
+        rm.hint_frame_locations[b2] = loc
+        rm.force_spill_var(b2)
+        loc2 = rm.loc(b2)
+        assert loc2 is not loc1     # because it's not in freed_frame_locations
+        #
+        rm._check_invariants()
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -690,6 +690,7 @@
 
     def _assemble(self, regalloc, operations):
         self._regalloc = regalloc
+        regalloc.compute_hint_frame_locations(operations)
         regalloc.walk_operations(operations)
         if we_are_translated() or self.cpu.dont_keepalive_stuff:
             self._regalloc = None   # else keep it around for debugging
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -1318,6 +1318,29 @@
             self.rm.possibly_free_var(tmpbox_low)
         self.rm.possibly_free_var(tmpbox_high)
 
+    def compute_hint_frame_locations(self, operations):
+        # optimization only: fill in the 'hint_frame_locations' dictionary
+        # of rm and xrm based on the JUMP at the end of the loop, by looking
+        # at where we would like the boxes to be after the jump.
+        op = operations[-1]
+        if op.getopnum() != rop.JUMP:
+            return
+        descr = op.getdescr()
+        assert isinstance(descr, LoopToken)
+        nonfloatlocs, floatlocs = self.assembler.target_arglocs(descr)
+        for i in range(op.numargs()):
+            box = op.getarg(i)
+            if isinstance(box, Box):
+                loc = nonfloatlocs[i]
+                if isinstance(loc, StackLoc):
+                    assert box.type != FLOAT
+                    self.rm.hint_frame_locations[box] = loc
+                else:
+                    loc = floatlocs[i]
+                    if isinstance(loc, StackLoc):
+                        assert box.type == FLOAT
+                        self.xrm.hint_frame_locations[box] = loc
+
     def consider_jump(self, op):
         assembler = self.assembler
         assert self.jump_target_descr is None
diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py
--- a/pypy/objspace/std/iterobject.py
+++ b/pypy/objspace/std/iterobject.py
@@ -33,9 +33,6 @@
     """Sequence iterator specialized for lists, accessing
     directly their RPython-level list of wrapped objects.
     """
-    def __init__(w_self, w_seq):
-        W_AbstractSeqIterObject.__init__(w_self, w_seq)
-        w_self.w_seq = w_seq
 
 class W_FastTupleIterObject(W_AbstractSeqIterObject):
    """Sequence iterator specialized for tuples, accessing
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -9,8 +9,9 @@
 from pypy.interpreter import gateway, baseobjspace
 from pypy.rlib.objectmodel import instantiate, specialize
 from pypy.rlib.listsort import make_timsort_class
-from pypy.rlib import rerased, jit
+from pypy.rlib import rerased, jit, debug
 from pypy.interpreter.argument import Signature
+from pypy.tool.sourcetools import func_with_new_name
 
 UNROLL_CUTOFF = 5
 
@@ -170,6 +171,19 @@
         share with the storage, if possible."""
         return self.strategy.getitems(self)
 
+    def getitems_fixedsize(self):
+        """Returns a fixed-size list of all items after wrapping them."""
+        l = self.strategy.getitems_fixedsize(self)
+        debug.make_sure_not_resized(l)
+        return l
+
+    def getitems_unroll(self):
+        """Returns a fixed-size list of all items after wrapping them. The JIT
+        will fully unroll this function.  """
+        l = self.strategy.getitems_unroll(self)
+        debug.make_sure_not_resized(l)
+        return l
+
     def getitems_copy(self):
         """Returns a copy of all items in the list. Same as getitems except for
         ObjectListStrategy."""
@@ -366,6 +380,8 @@
 
     def getitems_copy(self, w_list):
         return []
+    getitems_fixedsize = func_with_new_name(getitems_copy, "getitems_fixedsize")
+    getitems_unroll = getitems_fixedsize
 
     def getstorage_copy(self, w_list):
         return self.erase(None)
@@ -496,7 +512,6 @@
         # tuple is unmutable
         return w_list.lstorage
 
-
     @specialize.arg(2)
     def _getitems_range(self, w_list, wrap_items):
         l = self.unerase(w_list.lstorage)
@@ -519,6 +534,13 @@
 
         return r
 
+    @jit.dont_look_inside
+    def getitems_fixedsize(self, w_list):
+        return self._getitems_range_unroll(w_list, True)
+    def getitems_unroll(self, w_list):
+        return self._getitems_range_unroll(w_list, True)
+    _getitems_range_unroll = jit.unroll_safe(func_with_new_name(_getitems_range, "_getitems_range_unroll"))
+
     def getslice(self, w_list, start, stop, step, length):
         v = self.unerase(w_list.lstorage)
         old_start = v[0]
@@ -676,6 +698,13 @@
     def getitems_copy(self, w_list):
         return [self.wrap(item) for item in self.unerase(w_list.lstorage)]
 
+    @jit.unroll_safe
+    def getitems_unroll(self, w_list):
+        return [self.wrap(item) for item in self.unerase(w_list.lstorage)]
+    @jit.dont_look_inside
+    def getitems_fixedsize(self, w_list):
+        return self.getitems_unroll(w_list)
+
     def getstorage_copy(self, w_list):
         items = self.unerase(w_list.lstorage)[:]
         return self.erase(items)
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -408,8 +408,10 @@
         if isinstance(w_obj, W_AbstractTupleObject):
             t = w_obj.tolist()
         elif isinstance(w_obj, W_ListObject):
-            # XXX this can copy twice
-            t = w_obj.getitems()[:]
+            if unroll:
+                t = w_obj.getitems_unroll()
+            else:
+                t = w_obj.getitems_fixedsize()
         else:
             if unroll:
                 return make_sure_not_resized(ObjSpace.unpackiterable_unroll(
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -48,6 +48,46 @@
         for i in range(7):
             assert self.space.eq_w(l[i], l2[i])
 
+    def test_getitems_fixedsize(self):
+        w = self.space.wrap
+        from pypy.objspace.std.listobject import make_range_list
+        rangelist = make_range_list(self.space, 1,1,7)
+        emptylist = W_ListObject(self.space, [])
+        intlist = W_ListObject(self.space, [w(1),w(2),w(3),w(4),w(5),w(6),w(7)])
+        strlist = W_ListObject(self.space, [w('1'),w('2'),w('3'),w('4'),w('5'),w('6'),w('7')])
+        floatlist = W_ListObject(self.space, [w(1.0),w(2.0),w(3.0),w(4.0),w(5.0),w(6.0),w(7.0)])
+        objlist = W_ListObject(self.space, [w(1),w('2'),w(3.0),w(4),w(5),w(6),w(7)])
+
+        emptylist_copy = emptylist.getitems_fixedsize()
+        assert emptylist_copy == []
+
+        rangelist_copy = rangelist.getitems_fixedsize()
+        intlist_copy = intlist.getitems_fixedsize()
+        strlist_copy = strlist.getitems_fixedsize()
+        floatlist_copy = floatlist.getitems_fixedsize()
+        objlist_copy = objlist.getitems_fixedsize()
+        for i in range(7):
+            assert self.space.eq_w(rangelist_copy[i], rangelist.getitem(i))
+            assert self.space.eq_w(intlist_copy[i], intlist.getitem(i))
+            assert self.space.eq_w(strlist_copy[i], strlist.getitem(i))
+            assert self.space.eq_w(floatlist_copy[i], floatlist.getitem(i))
+            assert self.space.eq_w(objlist_copy[i], objlist.getitem(i))
+
+        emptylist_copy = emptylist.getitems_unroll()
+        assert emptylist_copy == []
+
+        rangelist_copy = rangelist.getitems_unroll()
+        intlist_copy = intlist.getitems_unroll()
+        strlist_copy = strlist.getitems_unroll()
+        floatlist_copy = floatlist.getitems_unroll()
+        objlist_copy = objlist.getitems_unroll()
+        for i in range(7):
+            assert self.space.eq_w(rangelist_copy[i], rangelist.getitem(i))
+            assert self.space.eq_w(intlist_copy[i], intlist.getitem(i))
+            assert self.space.eq_w(strlist_copy[i], strlist.getitem(i))
+            assert self.space.eq_w(floatlist_copy[i], floatlist.getitem(i))
+            assert self.space.eq_w(objlist_copy[i], objlist.getitem(i))
+
     def test_random_getitem(self):
         w = self.space.wrap
         s = list('qedx387tn3uixhvt 7fh387fymh3dh238 dwd-wq.dwq9')


More information about the pypy-commit mailing list