[pypy-svn] r12939 - in pypy/dist/pypy: annotation rpython rpython/test translator/test

arigo at codespeak.net arigo at codespeak.net
Tue May 31 19:13:21 CEST 2005


Author: arigo
Date: Tue May 31 19:13:21 2005
New Revision: 12939

Modified:
   pypy/dist/pypy/annotation/bookkeeper.py
   pypy/dist/pypy/annotation/builtin.py
   pypy/dist/pypy/annotation/listdef.py
   pypy/dist/pypy/rpython/rbuiltin.py
   pypy/dist/pypy/rpython/rint.py
   pypy/dist/pypy/rpython/rlist.py
   pypy/dist/pypy/rpython/test/test_rlist.py
   pypy/dist/pypy/translator/test/test_annrpython.py
Log:
Support for range objects in the rtyper, based on the annotator's deduction of
whether a variable can only contain a list which is a range with a known step.


Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py	(original)
+++ pypy/dist/pypy/annotation/bookkeeper.py	Tue May 31 19:13:21 2005
@@ -87,18 +87,19 @@
             self.userclasseslist.append(cdef)
             return self.userclasses[cls]
 
-    def getlistdef(self):
+    def getlistdef(self, **flags):
         """Get the ListDef associated with the current position."""
         try:
             listdef = self.listdefs[self.position_key]
         except KeyError:
             listdef = self.listdefs[self.position_key] = ListDef(self)
+            listdef.listitem.__dict__.update(flags)
         return listdef
 
-    def newlist(self, *s_values):
+    def newlist(self, *s_values, **flags):
         """Make a SomeList associated with the current position, general
         enough to contain the s_values as items."""
-        listdef = self.getlistdef()
+        listdef = self.getlistdef(**flags)
         for s_value in s_values:
             listdef.generalize(s_value)
         return SomeList(listdef)

Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py	(original)
+++ pypy/dist/pypy/annotation/builtin.py	Tue May 31 19:13:21 2005
@@ -38,7 +38,27 @@
 # ____________________________________________________________
 
 def builtin_range(*args):
-    return getbookkeeper().newlist(SomeInteger())  # XXX nonneg=...
+    s_step = immutablevalue(1)
+    if len(args) == 1:
+        s_start = immutablevalue(0)
+        s_stop = args[0]
+    elif len(args) == 2:
+        s_start, s_stop = args
+    elif len(args) == 3:
+        s_start, s_stop = args[:2]
+        s_step = args[2]
+    else:
+        raise Exception, "range() takes 1 to 3 arguments"
+    if not s_step.is_constant():
+        raise Exception, "range() step argument should be a constant"
+    step = s_step.const
+    if step == 0:
+        raise Exception, "range() with step zero"
+    elif step > 0:
+        nonneg = s_start.nonneg
+    else:
+        nonneg = s_stop.nonneg or (s_stop.is_constant() and s_stop.const >= -1)
+    return getbookkeeper().newlist(SomeInteger(nonneg=nonneg), range_step=step)
 
 builtin_xrange = builtin_range # xxx for now allow it
 

Modified: pypy/dist/pypy/annotation/listdef.py
==============================================================================
--- pypy/dist/pypy/annotation/listdef.py	(original)
+++ pypy/dist/pypy/annotation/listdef.py	Tue May 31 19:13:21 2005
@@ -5,6 +5,7 @@
 class ListItem:
     mutated = False    # True for lists mutated after creation
     resized = False    # True for lists resized after creation
+    range_step = None  # the step -- only for lists only created by a range()
 
     def __init__(self, bookkeeper, s_value):
         self.s_value = s_value
@@ -18,6 +19,8 @@
                 raise UnionError("merging list/dict items")
             self.mutated |= other.mutated
             self.resized |= other.resized
+            if other.range_step != self.range_step:
+                self.range_step = None
             self.itemof.update(other.itemof)
             self.read_locations.update(other.read_locations)
             self.patch()    # which should patch all refs to 'other'

Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/rbuiltin.py	Tue May 31 19:13:21 2005
@@ -3,6 +3,7 @@
 from pypy.rpython.lltype import malloc, typeOf, nullptr, nullgcptr
 from pypy.rpython.lltype import Void, Signed
 from pypy.rpython.rtyper import TyperError
+from pypy.rpython.rlist import rtype_builtin_range
 
 
 class __extend__(SomeBuiltin):
@@ -60,6 +61,8 @@
     assert hop.nb_args == 1
     return hop.args_s[0].rtype_float(hop)
 
+#def rtype_builtin_range(hop): see rlist.py
+
 
 # collect all functions
 import __builtin__

Modified: pypy/dist/pypy/rpython/rint.py
==============================================================================
--- pypy/dist/pypy/rpython/rint.py	(original)
+++ pypy/dist/pypy/rpython/rint.py	Tue May 31 19:13:21 2005
@@ -46,6 +46,10 @@
         return _rtype_template(hop, 'div')
     rtype_inplace_div = rtype_div
 
+    def rtype_floordiv(_, hop):
+        return _rtype_template(hop, 'floordiv')
+    rtype_inplace_floordiv = rtype_floordiv
+
     def rtype_mod(_, hop):
         return _rtype_template(hop, 'mod')
     rtype_inplace_mod = rtype_mod

Modified: pypy/dist/pypy/rpython/rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/rlist.py	(original)
+++ pypy/dist/pypy/rpython/rlist.py	Tue May 31 19:13:21 2005
@@ -1,5 +1,6 @@
 from pypy.annotation.pairtype import pair, pairtype
 from pypy.annotation.model import SomeList, SomeInteger
+from pypy.objspace.flow.model import Constant
 from pypy.rpython.lltype import *
 
 # ____________________________________________________________
@@ -13,22 +14,45 @@
 #    'items' points to a C-like array in memory preceded by a 'length' header,
 #    where each item contains a primitive value or pointer to the actual list
 #    item.
+#
+#    Lists returned by range() and never mutated use a simpler implementation:
+#
+#    struct range {
+#        Signed start, stop;    // step is always constant
+#    }
+
+RANGE = GcStruct("range", ("start", Signed), ("stop", Signed))
+
 
 class __extend__(SomeList):
 
+    def ll_range_step(s_list):
+        return (not s_list.listdef.listitem.mutated
+                and s_list.listdef.listitem.range_step)
+
     def lowleveltype(s_list):
-        ITEM = s_list.get_s_items().lowleveltype()
-        LIST = GcStruct("list", ("items", GcPtr(GcArray(("item", ITEM)))))
-        return GcPtr(LIST)
+        if s_list.ll_range_step():
+            assert isinstance(s_list.get_s_items(), SomeInteger)
+            return GcPtr(RANGE)
+        else:
+            ITEM = s_list.get_s_items().lowleveltype()
+            LIST = GcStruct("list", ("items", GcPtr(GcArray(("item", ITEM)))))
+            return GcPtr(LIST)
 
     def get_s_items(s_list):
         return s_list.listdef.listitem.s_value
 
     def rtype_len(s_lst, hop):
         v_lst, = hop.inputargs(s_lst)
-        return hop.gendirectcall(ll_len, v_lst)
+        step = s_lst.ll_range_step()
+        if step:
+            cstep = hop.inputconst(Signed, step)
+            return hop.gendirectcall(ll_rangelen, v_lst, cstep)
+        else:
+            return hop.gendirectcall(ll_len, v_lst)
 
     def rtype_method_append(s_lst, hop):
+        assert not s_lst.ll_range_step()
         v_lst, v_value = hop.inputargs(s_lst, s_lst.get_s_items())
         hop.gendirectcall(ll_append, v_lst, v_value)
 
@@ -37,11 +61,16 @@
 
     def rtype_getitem((s_lst1, s_int2), hop):
         v_lst, v_index = hop.inputargs(s_lst1, Signed)
-        if s_int2.nonneg:
-            llfn = ll_getitem_nonneg
+        step = s_lst1.ll_range_step()
+        if step:
+            cstep = hop.inputconst(Signed, step)
+            return hop.gendirectcall(ll_rangeitem, v_lst, v_index, cstep)
         else:
-            llfn = ll_getitem
-        return hop.gendirectcall(llfn, v_lst, v_index)
+            if s_int2.nonneg:
+                llfn = ll_getitem_nonneg
+            else:
+                llfn = ll_getitem
+            return hop.gendirectcall(llfn, v_lst, v_index)
 
 
 # ____________________________________________________________
@@ -71,9 +100,36 @@
         i += len(l.items)
     return l.items[i].item
 
+def ll_setitem(l, i, newitem):
+    if i<0:
+        i += len(l.items)
+    l.items[i].item = newitem
+
 def ll_setitem_nonneg(l, i, newitem):
     l.items[i].item = newitem
 
+# __________ range __________
+
+def ll_rangelen(l, step):
+    if step > 0:
+        result = (l.stop - l.start + (step-1)) // step
+    else:
+        result = (l.start - l.stop - (step+1)) // (-step)
+    if result < 0:
+        result = 0
+    return result
+
+def ll_rangeitem(l, i, step):
+    if i<0:
+        # XXX ack. cannot call ll_rangelen() here for now :-(
+        if step > 0:
+            length = (l.stop - l.start + (step-1)) // step
+        else:
+            length = (l.start - l.stop - (step+1)) // (-step)
+        #assert length >= 0
+        i += length
+    return l.start + i*step
+
 # ____________________________________________________________
 #
 #  Irregular operations.
@@ -95,3 +151,24 @@
         v_item = hop.inputarg(s_listitem, arg=i)
         hop.gendirectcall(ll_setitem_nonneg, v_result, ci, v_item)
     return v_result
+
+def ll_newrange(start, stop):
+    l = malloc(RANGE)
+    l.start = start
+    l.stop = stop
+    return l
+
+def rtype_builtin_range(hop):
+    s_range = hop.s_result
+    step = s_range.listdef.listitem.range_step
+    if step is None:   # cannot build a RANGE object, needs a real list
+        raise TyperError("range() list used too dynamically")
+    if hop.nb_args == 1:
+        vstart = hop.inputconst(Signed, 0)
+        vstop, = hop.inputargs(Signed)
+    elif hop.nb_args == 2:
+        vstart, vstop = hop.inputargs(Signed, Signed)
+    else:
+        vstart, vstop, vstep = hop.inputargs(Signed, Signed, Signed)
+        assert isinstance(vstep, Constant) and vstep.value == step
+    return hop.gendirectcall(ll_newrange, vstart, vstop)

Modified: pypy/dist/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rlist.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rlist.py	Tue May 31 19:13:21 2005
@@ -1,8 +1,42 @@
 from pypy.translator.translator import Translator
+from pypy.annotation.listdef import ListDef
 from pypy.rpython.lltype import *
 from pypy.rpython.rtyper import RPythonTyper
+from pypy.rpython.rlist import *
 
 
+def test_rlist():
+    s = SomeList(ListDef(None, SomeInteger()))
+    l = ll_newlist(s.lowleveltype(), 3)
+    ll_setitem(l, 0, 42)
+    ll_setitem(l, -2, 43)
+    ll_setitem_nonneg(l, 2, 44)
+    ll_append(l, 45)
+    assert ll_getitem(l, -4) == 42
+    assert ll_getitem_nonneg(l, 1) == 43
+    assert ll_getitem(l, 2) == 44
+    assert ll_getitem(l, 3) == 45
+    assert ll_len(l) == 4
+
+def test_rlist_range():
+    def test1(start, stop, step):
+        expected = range(start, stop, step)
+        length = len(expected)
+        l = ll_newrange(start, stop)
+        assert ll_rangelen(l, step) == length
+        lst = [ll_rangeitem(l, i, step) for i in range(length)]
+        assert lst == expected
+        lst = [ll_rangeitem(l, i-length, step) for i in range(length)]
+        assert lst == expected
+
+    for start in (-10, 0, 1, 10):
+        for stop in (-8, 0, 4, 8, 25):
+            for step in (1, 2, 3, -1, -2):
+                test1(start, stop, step)
+
+
+# ____________________________________________________________
+
 def test_simple():
     def dummyfn():
         l = [10,20,30]
@@ -42,3 +76,19 @@
     typer.specialize()
     #t.view()
     t.checkgraphs()
+
+
+def test_range():
+    def dummyfn(N):
+        total = 0
+        total = len(range(N))
+        #for i in :
+        #    total += i
+        return total
+
+    t = Translator(dummyfn)
+    t.annotate([])
+    typer = RPythonTyper(t.annotator)
+    typer.specialize()
+    #t.view()
+    t.checkgraphs()

Modified: pypy/dist/pypy/translator/test/test_annrpython.py
==============================================================================
--- pypy/dist/pypy/translator/test/test_annrpython.py	(original)
+++ pypy/dist/pypy/translator/test/test_annrpython.py	Tue May 31 19:13:21 2005
@@ -736,6 +736,7 @@
             if isinstance(s_value, annmodel.SomeList):
                 assert not s_value.listdef.listitem.resized
                 assert not s_value.listdef.listitem.mutated
+                assert s_value.listdef.listitem.is_range
 
     def test_bool(self):
         def f(a,b):



More information about the Pypy-commit mailing list