[pypy-svn] r67695 - in pypy/trunk/pypy: annotation config doc/discussion rpython rpython/lltypesystem rpython/ootypesystem translator/test

antocuni at codespeak.net antocuni at codespeak.net
Tue Sep 15 16:40:45 CEST 2009


Author: antocuni
Date: Tue Sep 15 16:40:44 2009
New Revision: 67695

Removed:
   pypy/trunk/pypy/doc/discussion/list_comprehension_ootype.txt
Modified:
   pypy/trunk/pypy/annotation/unaryop.py
   pypy/trunk/pypy/config/translationoption.py
   pypy/trunk/pypy/rpython/lltypesystem/rlist.py
   pypy/trunk/pypy/rpython/ootypesystem/rlist.py
   pypy/trunk/pypy/rpython/rlist.py
   pypy/trunk/pypy/translator/test/test_simplify.py
Log:
enable list comprehension optimization for ootype.  This is slightly more
convoluted than in lltype because there is no simple way to convert from an
ootype.List to an ootype.Array apart copying item by item. Thus, to optimize
the common case instead of a List we use a temporary record holding an array
and the length.  For the other cases, items are just copied one by one



Modified: pypy/trunk/pypy/annotation/unaryop.py
==============================================================================
--- pypy/trunk/pypy/annotation/unaryop.py	(original)
+++ pypy/trunk/pypy/annotation/unaryop.py	Tue Sep 15 16:40:44 2009
@@ -342,6 +342,8 @@
             # not over an iterator object (because it has no known length)
             s_iterable = args_s[0]
             if isinstance(s_iterable, (SomeList, SomeDict)):
+                lst = SomeList(lst.listdef) # create a fresh copy
+                lst.known_maxlength = True
                 lst.listdef.resize()
                 lst.listdef.listitem.hint_maxlength = True
         elif 'fence' in hints:

Modified: pypy/trunk/pypy/config/translationoption.py
==============================================================================
--- pypy/trunk/pypy/config/translationoption.py	(original)
+++ pypy/trunk/pypy/config/translationoption.py	Tue Sep 15 16:40:44 2009
@@ -29,7 +29,6 @@
                                 ("translation.backendopt.constfold", False),
                                 ("translation.backendopt.heap2stack", False),
                                 ("translation.backendopt.clever_malloc_removal", False),
-                                ("translation.list_comprehension_operations", False),
                                 ("translation.gc", "boehm"), # it's not really used, but some jit code expects a value here
                                 ]
                      }),

Modified: pypy/trunk/pypy/rpython/lltypesystem/rlist.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/rlist.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/rlist.py	Tue Sep 15 16:40:44 2009
@@ -41,7 +41,8 @@
 class BaseListRepr(AbstractBaseListRepr):
     rstr_ll = rstr.LLHelpers
 
-    def __init__(self, rtyper, item_repr, listitem=None):
+    # known_maxlength is ignored by lltype but used by ootype
+    def __init__(self, rtyper, item_repr, listitem=None, known_maxlength=False):
         self.rtyper = rtyper
         self.LIST = GcForwardReference()
         self.lowleveltype = Ptr(self.LIST)
@@ -136,15 +137,8 @@
         hints = hop.args_s[-1].const
         if 'maxlength' in hints:
             if optimized:
-                v_iterable = hop.args_v[1]
-                s_iterable = hop.args_s[1]
-                r_iterable = hop.args_r[1]
                 v_list = hop.inputarg(self, arg=0)
-                hop2 = hop.copy()
-                while hop2.nb_args > 0:
-                    hop2.r_s_popfirstarg()
-                hop2.v_s_insertfirstarg(v_iterable, s_iterable)
-                v_maxlength = r_iterable.rtype_len(hop2)
+                v_maxlength = self._get_v_maxlength(hop)
                 hop.llops.gendirectcall(ll_set_maxlength, v_list, v_maxlength)
                 return v_list
         if 'fence' in hints:

Modified: pypy/trunk/pypy/rpython/ootypesystem/rlist.py
==============================================================================
--- pypy/trunk/pypy/rpython/ootypesystem/rlist.py	(original)
+++ pypy/trunk/pypy/rpython/ootypesystem/rlist.py	Tue Sep 15 16:40:44 2009
@@ -11,7 +11,7 @@
 class BaseListRepr(AbstractBaseListRepr):
     rstr_ll = rstr.LLHelpers
 
-    def __init__(self, rtyper, item_repr, listitem=None):
+    def __init__(self, rtyper, item_repr, listitem=None, known_maxlength=False):
         self.rtyper = rtyper
         if not isinstance(item_repr, Repr):
             assert callable(item_repr)
@@ -19,6 +19,7 @@
         else:
             self.external_item_repr, self.item_repr = \
                     externalvsinternal(rtyper, item_repr)
+        self.known_maxlength = known_maxlength
         self.LIST = self._make_empty_type()
         self.lowleveltype = self.LIST
         self.listitem = listitem
@@ -29,8 +30,14 @@
         if 'item_repr' not in self.__dict__:
             self.external_item_repr, self.item_repr = \
                     self._externalvsinternal(self.rtyper, self._item_repr_computer())
-        if not ootype.hasItemType(self.lowleveltype):
-            ootype.setItemType(self.lowleveltype, self.item_repr.lowleveltype)
+        if not self._hasItemType(self.lowleveltype):
+            self._setItemType(self.lowleveltype, self.item_repr.lowleveltype)
+
+    def _hasItemType(self, LIST):
+        return ootype.hasItemType(LIST)
+
+    def _setItemType(self, LIST, ITEM):
+        ootype.setItemType(LIST, ITEM)
 
     def _externalvsinternal(self, rtyper, item_repr):
         return item_repr, item_repr
@@ -49,15 +56,57 @@
 
     def rtype_hint(self, hop):
         hints = hop.args_s[-1].const
-        if 'maxlength' in hints or 'fence' in hints:
-            # see doc/discussion/list_comprehension_ootype.txt
-            assert False, 'TODO'
+        optimized = getattr(self.listitem, 'hint_maxlength', False)
+        if optimized and 'maxlength' in hints:
+            return self.rtype_hint_maxlength(hop)
+        elif 'fence' in hints:
+            return self.rtype_hint_fence(hop)
         return AbstractBaseListRepr.rtype_hint(self, hop)
 
+    def rtype_hint_maxlength(self, hop):
+        v_maxlength = self._get_v_maxlength(hop)
+        RESLIST = hop.r_result.LIST
+        _, ARRAY = RESLIST._lookup_field('items')
+        cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
+        cARRAY = hop.inputconst(Void, ARRAY)            
+        return hop.llops.gendirectcall(ll_newlist_maxlength, cRESLIST, cARRAY, v_maxlength)
+
+    def rtype_hint_fence(self, hop):
+        hints = hop.args_s[-1].const
+        v_list = hop.inputarg(self, arg=0)
+        RESLIST = hop.r_result.LIST
+        cRESLIST = hop.inputconst(Void, hop.r_result.LIST)
+        if self.known_maxlength:
+            if isinstance(hop.r_result, FixedSizeListRepr):
+                if 'exactlength' in hints:
+                    llfn = ll_known_maxlength2fixed_exact
+                else:
+                    llfn = ll_known_maxlength2fixed
+            else:
+                llfn = ll_known_maxlength2list
+        else:
+            llfn = ll_list2fixed
+        return hop.llops.gendirectcall(llfn, cRESLIST, v_list)
+
 
 class ListRepr(AbstractListRepr, BaseListRepr):
+
+    def _hasItemType(self, LIST):
+        if self.known_maxlength:
+            _, ARRAY = LIST._lookup_field('items')
+            return ootype.hasItemType(ARRAY)
+        else:
+            return ootype.hasItemType(LIST)
+
+    def _setItemType(self, LIST, ITEM):
+        if self.known_maxlength:
+            _, ARRAY = LIST._lookup_field('items')
+            ootype.setItemType(ARRAY, ITEM)
+        else:
+            ootype.setItemType(LIST, ITEM)
+
     def null_const(self):
-        return self.LIST._null
+        return ootype.null(self.LIST)
 
     def prepare_const(self, n):
         result = self.LIST.ll_newlist(n)
@@ -67,7 +116,10 @@
         return ListIteratorRepr(self)
 
     def _make_empty_type(self):
-        return ootype.List()
+        if self.known_maxlength:
+            return ootype.Record({"items": ootype.Array(), "length": ootype.Signed})
+        else:
+            return ootype.List()
 
     def _generate_newlist(self, llops, items_v):
         c_list = inputconst(ootype.Void, self.lowleveltype)
@@ -77,6 +129,15 @@
         llops.genop("oosend", [c_resize, v_result, c_length], resulttype=ootype.Void)
         return v_result
 
+    def rtype_method_append(self, hop):
+        if self.known_maxlength:
+            v_lst, v_value = hop.inputargs(self, self.item_repr)
+            hop.exception_cannot_occur()
+            hop.gendirectcall(ll_append_maxlength, v_lst, v_value)
+        else:
+            return AbstractListRepr.rtype_method_append(self, hop)
+
+
 class __extend__(pairtype(BaseListRepr, BaseListRepr)):
 
     def rtype_is_((r_lst1, r_lst2), hop):
@@ -100,6 +161,50 @@
     lst._ll_resize(length)
     return lst
 
+# lists with known_maxlength
+def ll_newlist_maxlength(LIST, ARRAY, length):
+    lst = ootype.new(LIST)
+    lst.items = ootype.oonewarray(ARRAY, length)
+    lst.length = 0
+    return lst
+
+def ll_append_maxlength(l, newitem):
+    l.items.ll_setitem_fast(l.length, newitem)
+    l.length += 1
+
+def ll_known_maxlength2fixed(ARRAY, l):
+    n = l.length
+    olditems = l.items
+    if n == olditems.ll_length():
+        return olditems
+    else:
+        newitems = ootype.oonewarray(ARRAY, n)
+        for i in range(n):
+            item = olditems.ll_getitem_fast(i)
+            newitems.ll_setitem_fast(i, item)
+        return newitems
+ll_known_maxlength2fixed.oopspec = 'list.list2fixed(l)'
+
+def ll_known_maxlength2fixed_exact(ARRAY, l):
+    return l.items
+
+def ll_known_maxlength2list(RESLIST, l):
+    res = ootype.new(RESLIST)
+    length = l.length
+    res._ll_resize_ge(length)
+    for i in range(length):
+        item = l.items.ll_getitem_fast(i)
+        res.ll_setitem_fast(i, item)
+    return res
+
+def ll_list2fixed(RESLIST, l):
+    length = l.ll_length()
+    res = ootype.oonewarray(RESLIST, length)
+    for i in range(length):
+        item = l.ll_getitem_fast(i)
+        res.ll_setitem_fast(i, item)
+    return res
+
 # Fixed-size list 
 class FixedSizeListRepr(AbstractFixedSizeListRepr, BaseListRepr):
     def compact_repr(self):

Modified: pypy/trunk/pypy/rpython/rlist.py
==============================================================================
--- pypy/trunk/pypy/rpython/rlist.py	(original)
+++ pypy/trunk/pypy/rpython/rlist.py	Tue Sep 15 16:40:44 2009
@@ -42,16 +42,17 @@
             # cannot do the rtyper.getrepr() call immediately, for the case
             # of recursive structures -- i.e. if the listdef contains itself
             rlist = rtyper.type_system.rlist
+            item_repr = lambda: rtyper.getrepr(listitem.s_value)
+            known_maxlength = getattr(self, 'known_maxlength', False)
             if self.listdef.listitem.resized:
-                return rlist.ListRepr(rtyper,
-                        lambda: rtyper.getrepr(listitem.s_value), listitem)
+                return rlist.ListRepr(rtyper, item_repr, listitem, known_maxlength)
             else:
-                return rlist.FixedSizeListRepr(rtyper,
-                        lambda: rtyper.getrepr(listitem.s_value), listitem)
+                return rlist.FixedSizeListRepr(rtyper, item_repr, listitem)
 
     def rtyper_makekey(self):
         self.listdef.listitem.dont_change_any_more = True
-        return self.__class__, self.listdef.listitem
+        known_maxlength = getattr(self, 'known_maxlength', False)
+        return self.__class__, self.listdef.listitem, known_maxlength
 
 
 class AbstractBaseListRepr(Repr):
@@ -160,6 +161,17 @@
         item_eq_func = self.item_repr.get_ll_eq_function()
         return list_eq
 
+    def _get_v_maxlength(self, hop):
+        v_iterable = hop.args_v[1]
+        s_iterable = hop.args_s[1]
+        r_iterable = hop.args_r[1]
+        hop2 = hop.copy()
+        while hop2.nb_args > 0:
+            hop2.r_s_popfirstarg()
+        hop2.v_s_insertfirstarg(v_iterable, s_iterable)
+        v_maxlength = r_iterable.rtype_len(hop2)
+        return v_maxlength
+
 
 class AbstractListRepr(AbstractBaseListRepr):
 

Modified: pypy/trunk/pypy/translator/test/test_simplify.py
==============================================================================
--- pypy/trunk/pypy/translator/test/test_simplify.py	(original)
+++ pypy/trunk/pypy/translator/test/test_simplify.py	Tue Sep 15 16:40:44 2009
@@ -348,8 +348,7 @@
         if conftest.option.view:
             t.view()
         t.buildrtyper(self.typesystem).specialize()
-        if self.typesystem == 'lltype':
-            backend_optimizations(t)
+        backend_optimizations(t)
         if conftest.option.view:
             t.view()
         graph = graphof(t, func)
@@ -364,6 +363,14 @@
         res = interp.eval_graph(graph, [10])
         assert res == 5 * 17
 
+    def test_simple_non_exact(self):
+        def main(n):
+            lst = [x*17 for x in range(n) if x < 5]
+            return len(lst)
+        interp, graph = self.specialize(main, [int])
+        res = interp.eval_graph(graph, [10])
+        assert res == 5
+
     def test_mutated_after_listcomp(self):
         def main(n):
             lst = [x*17 for x in range(n)]
@@ -424,7 +431,6 @@
         res = interp.eval_graph(graph, [10])
         assert res == 5 * 17
 
-## TODO: maxlength and fence hints are not supported by ootype
-## see doc/discussion/list_comprehension_ootype.txt
-##class TestOOSpecializeListComprehension(TestLLSpecializeListComprehension):
-##    typesystem = 'ootype'
+
+class TestOOSpecializeListComprehension(TestLLSpecializeListComprehension):
+   typesystem = 'ootype'



More information about the Pypy-commit mailing list