[pypy-svn] r20197 - in pypy/branch/somepbc-refactoring/pypy: annotation rpython rpython/lltypesystem

arigo at codespeak.net arigo at codespeak.net
Wed Nov 23 20:02:21 CET 2005


Author: arigo
Date: Wed Nov 23 20:02:20 2005
New Revision: 20197

Modified:
   pypy/branch/somepbc-refactoring/pypy/annotation/description.py
   pypy/branch/somepbc-refactoring/pypy/rpython/lltypesystem/lltype.py
   pypy/branch/somepbc-refactoring/pypy/rpython/normalizecalls.py
   pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py
   pypy/branch/somepbc-refactoring/pypy/rpython/rtyper.py
Log:
(pedronis, arigo)

progress.  The table of concrete function pointers is now computed
and compressed correctly, hopefully.



Modified: pypy/branch/somepbc-refactoring/pypy/annotation/description.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/annotation/description.py	(original)
+++ pypy/branch/somepbc-refactoring/pypy/annotation/description.py	Wed Nov 23 20:02:20 2005
@@ -15,8 +15,11 @@
         self.patterns = {}    # set of "call shapes" in the sense of
                               # pypy.interpreter.argument.Argument
         self.calltables = {}  # see calltable_lookup_row()
+        self.total_calltable_size = 0
 
     def update(self, other):
+        assert not self.calltables and not other.calltables, (
+            "too late for merging call families!")
         self.descs.update(other.descs)
         self.patterns.update(other.patterns)
 
@@ -27,42 +30,17 @@
         # There is one such table per "call shape".
         table = self.calltables.setdefault(callshape, [])
         for i, existing_row in enumerate(table):
-            # which row(s) can the new row be merged with?  The
-            # condition is to have at least a common graph, and no
-            # incompatible graphs elsewhere.
-            for desc, graph in row.items():
-                if existing_row.get(desc) is graph:
-                    # common graph.  Do we find incompatible graphs?
-                    merged = row.copy()
-                    merged.update(existing_row)
-                    for merged_desc, merged_graph in merged.items():
-                        if (merged_desc in row and
-                            row[merged_desc] is not merged_graph):
-                            msg = ("incompatible specializations in a call"
-                                   " to %r")
-                            raise Exception(msg % (merged_desc,))
-                    # done.
-                    return i, merged
-            #else: no common graph
+            if existing_row == row:   # XXX maybe use a dict again here?
+                return i
         raise LookupError
 
     def calltable_add_row(self, callshape, row):
-        table = self.calltables.setdefault(callshape, [])
-        while True:
-            try:
-                index, merged = self.calltable_lookup_row(callshape, row)
-            except LookupError:
-                # no compatible row.  Add this new one.
-                table.append(row)
-            else:
-                if merged != table[index]:
-                    # remove the existing row
-                    del table[index]
-                    # Start over again with this expanded row
-                    # which can possibly be further merged with other rows
-                    row = merged
-                    continue
-            return
+        try:
+            self.calltable_lookup_row(callshape, row)
+        except LookupError:
+            table = self.calltables.setdefault(callshape, [])
+            table.append(row)
+            self.total_calltable_size += 1
 
 
 class AttrFamily:

Modified: pypy/branch/somepbc-refactoring/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/somepbc-refactoring/pypy/rpython/lltypesystem/lltype.py	Wed Nov 23 20:02:20 2005
@@ -601,7 +601,7 @@
                 type(other).__name__,))
         if self._TYPE != other._TYPE:
             raise TypeError("comparing %r and %r" % (self._TYPE, other._TYPE))
-        return self._obj is other._obj
+        return self._obj == other._obj
 
     def __ne__(self, other):
         return not (self == other)

Modified: pypy/branch/somepbc-refactoring/pypy/rpython/normalizecalls.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/rpython/normalizecalls.py	(original)
+++ pypy/branch/somepbc-refactoring/pypy/rpython/normalizecalls.py	Wed Nov 23 20:02:20 2005
@@ -78,48 +78,32 @@
     nshapes = len(callfamily.calltables)
     for shape, table in callfamily.calltables.items():
         for row in table:
-            normalize_calltable_row_signature(annotator, shape, row, nshapes)
+            did_something = normalize_calltable_row_signature(annotator, shape,
+                                                              row)
+            if did_something:
+                assert nshapes == 1, "XXX call table too complex"
     while True: 
         progress = False
         for shape, table in callfamily.calltables.items():
             for row in table:
-                progress |= normalize_calltable_row_annotation(annotator, shape, row)
+                progress |= normalize_calltable_row_annotation(annotator, shape,
+                                                               row)
         if not progress:
             return   # done
-    else:
-        raise Exception("call table too complex, giving up")
-
-
-def sinputs(annotator, graph):
-    return [annotator.binding(a) for a in graph.getargs()]
-
-def sresult(annotator, graph):
-    if graph.getreturnvar() in annotator.bindings:
-        return annotator.binding(graph.getreturnvar())
-    else:
-        return annmodel.s_ImpossibleValue
 
-def sfullsig(annotator, graph):
-    return (graph.signature,
-            graph.defaults,
-            sinputs(annotator, graph),
-            sresult(annotator, graph))
 
-def normalize_calltable_row_signature(annotator, shape, row, nshapes):
+def normalize_calltable_row_signature(annotator, shape, row):
     graphs = row.values()
-    if not graphs:
-        return
+    assert graphs, "no graph??"
     sig0 = graphs[0].signature
     defaults0 = graphs[0].defaults
-    for graph in graphs:
+    for graph in graphs[1:]:
         if graph.signature != sig0:
             break
         if graph.defaults != defaults0:
             break
     else:
-        return
-    
-    assert nshapes == 1, "XXX was not supported"
+        return False   # nothing to do, all signatures already match
     
     shape_cnt, shape_keys, shape_star, shape_stst = shape
     assert not shape_star, "XXX not implemented"
@@ -129,6 +113,7 @@
     # a common type
     call_nbargs = shape_cnt + len(shape_keys)
 
+    did_something = False
     NODEFAULT = object()
 
     for graph in graphs:
@@ -186,7 +171,9 @@
             # finished
             checkgraph(graph)
             annotator.annotated[newblock] = annotator.annotated[oldblock]
-   
+            did_something = True
+    return did_something
+
 def normalize_calltable_row_annotation(annotator, shape, row):
     if len(row) <= 1:
         return False   # nothing to do
@@ -254,125 +241,6 @@
 
     return conversion
 
-def normalize_calltable_row(annotator, shape, row):
-    """Normalize a row of the call table, in the sense that all graphs
-    in that row should end up having the same signature (sfullsig()).
-    """
-    if len(row) <= 1:
-        return False   # nothing to do
-    
-    # 1. if all the same sfullsig(), happy ?????????????????????
-
-    sigs = [sfullsig(annotator, graph) for graph in row.itervalues()]
-
-    if dict.fromkeys(sigs) == 1:
-        return False
-
-    assert not shape[1] # no keyword arguments yet
-
-    # 2. if all the same graph.signature+graph.defaults, not too bad;
-    #    otherwise,  parse all graphs' signature according to 'shape'
-    #
-    # 3. hack the graphs for the (potentially new) signature, and the
-    #    unification of the annotations
-    
-    fully_normalized = True
-    if len(family.patterns) > 1:
-        argspec = inspect.getargspec(functions[0])
-        for func in functions:
-            if inspect.getargspec(func) != argspec:
-                raise TyperError("don't support multiple call patterns "
-                         "to multiple functions with different signatures for now %r" % (
-                        functions))
-        args, varargs, varkwds, _ = argspec
-        assert varargs is None, "XXX not implemented"
-        assert varkwds is None, "XXX not implemented"
-        pattern = (len(args), (), False, False)
-        fully_normalized = False
-    else:
-        pattern, = family.patterns
-    shape_cnt, shape_keys, shape_star, shape_stst = pattern
-    assert not shape_star, "XXX not implemented"
-    assert not shape_stst, "XXX not implemented"
-
-    # for the first 'shape_cnt' arguments we need to generalize to
-    # a common type
-    graph_bindings = {}
-    graph_argorders = {}
-    for func in functions:
-        assert not has_varargs(func), "XXX not implemented"
-        try:
-            graph = annotator.translator.flowgraphs[func]
-        except KeyError:
-            raise TyperError("the skipped %r must not show up in a "
-                             "call family" % (func,))
-        graph_bindings[graph] = [annotator.binding(v)
-                                 for v in graph.getargs()]
-        argorder = range(shape_cnt)
-        for key in shape_keys:
-            i = list(func.func_code.co_varnames).index(key)
-            assert i not in argorder
-            argorder.append(i)
-        graph_argorders[graph] = argorder
-
-    call_nbargs = shape_cnt + len(shape_keys)
-    generalizedargs = []
-    for i in range(call_nbargs):
-        args_s = []
-        for graph, bindings in graph_bindings.items():
-            j = graph_argorders[graph][i]
-            args_s.append(bindings[j])
-        s_value = annmodel.unionof(*args_s)
-        generalizedargs.append(s_value)
-    result_s = [annotator.binding(graph.getreturnvar())
-                for graph in graph_bindings]
-    generalizedresult = annmodel.unionof(*result_s)
-
-    for func in functions:
-        graph = annotator.translator.getflowgraph(func)
-        bindings = graph_bindings[graph]
-        argorder = graph_argorders[graph]
-        need_reordering = (argorder != range(call_nbargs))
-        need_conversion = (generalizedargs != bindings)
-        if need_reordering or need_conversion:
-            oldblock = graph.startblock
-            inlist = []
-            for s_value, j in zip(generalizedargs, argorder):
-                v = Variable(graph.getargs()[j])
-                annotator.setbinding(v, s_value)
-                inlist.append(v)
-            newblock = Block(inlist)
-            # prepare the output args of newblock:
-            # 1. collect the positional arguments
-            outlist = inlist[:shape_cnt]
-            # 2. add defaults and keywords
-            defaults = func.func_defaults or ()
-            for j in range(shape_cnt, len(bindings)):
-                try:
-                    i = argorder.index(j)
-                    v = inlist[i]
-                except ValueError:
-                    try:
-                        default = defaults[j-len(bindings)]
-                    except IndexError:
-                        raise TyperError(
-                            "call pattern has %d positional arguments, "
-                            "but %r takes at least %d arguments" % (
-                                shape_cnt, func,
-                                len(bindings) - len(defaults)))
-                    v = Constant(default)
-                outlist.append(v)
-            newblock.closeblock(Link(outlist, oldblock))
-            oldblock.isstartblock = False
-            newblock.isstartblock = True
-            graph.startblock = newblock
-            # finished
-            checkgraph(graph)
-            annotator.annotated[newblock] = annotator.annotated[oldblock]
-        graph.normalized_for_calls = fully_normalized
-        # convert the return value too
-        annotator.setbinding(graph.getreturnvar(), generalizedresult)
-
 
 def specialize_pbcs_by_memotables(annotator):
     memo_tables = annotator.bookkeeper.memo_tables

Modified: pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py	(original)
+++ pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py	Wed Nov 23 20:02:20 2005
@@ -68,6 +68,87 @@
         else:
             return hop.rtyper.type_system.check_null(self, hop)
 
+
+class ConcreteCallTableRow(dict):
+    """A row in a concrete call table."""
+
+def build_concrete_calltable(rtyper, callfamily):
+    """Build a complete call table of a call family
+    with concrete low-level function objs.
+    """
+    concretetable = {}   # (shape,index): row, maybe with duplicates
+    uniquerows = []      # list of rows, without duplicates
+    
+    def lookuprow(row):
+        # a 'matching' row is one that has the same llfn, expect
+        # that it may have more or less 'holes'
+        for existingindex, existingrow in enumerate(uniquerows):
+            for funcdesc, llfn in row.items():
+                if funcdesc in existingrow:
+                    if llfn != existingrow[funcdesc]:
+                        break   # mismatch
+            else:
+                # potential match, unless the two rows have no common funcdesc
+                merged = ConcreteCallTableRow(row)
+                merged.update(existingrow)
+                if len(merged) == len(row) + len(existingrow):
+                    pass   # no common funcdesc, not a match
+                else:
+                    return existingindex, merged
+        raise LookupError
+
+    def addrow(row):
+        # add a row to the table, potentially merging it with an existing row
+        try:
+            index, merged = lookuprow(row)
+        except LookupError:
+            uniquerows.append(row)   # new row
+        else:
+            if merged == uniquerows[index]:
+                pass    # already exactly in the table
+            else:
+                del uniquerows[index]
+                addrow(merged)   # add the potentially larger merged row
+
+    concreterows = {}
+    for shape, rows in callfamily.calltables.items():
+        for index, row in enumerate(rows):
+            concreterow = ConcreteCallTableRow()
+            for funcdesc, graph in row.items():
+                llfn = rtyper.getcallable(graph)
+                concreterow[funcdesc] = llfn
+            concreterows[shape, index] = concreterow
+
+    for row in concreterows.values():
+        addrow(row)
+
+    for (shape, index), row in concreterows.items():
+        _, biggerrow = lookuprow(row)
+        concretetable[shape, index] = biggerrow
+
+    for finalindex, row in enumerate(uniquerows):
+        row.attrname = 'variant%d' % finalindex
+
+    return concretetable, uniquerows
+
+def get_concrete_calltable(rtyper, callfamily):
+    """Get a complete call table of a call family
+    with concrete low-level function objs.
+    """
+    # cache on the callfamily
+    try:
+        cached = rtyper.concrete_calltables[callfamily]
+    except KeyError:
+        concretetable, uniquerows = build_concrete_calltable(rtyper, callfamily)
+        cached = concretetable, uniquerows, callfamily.total_calltable_size
+        rtyper.concrete_calltables[callfamily] = cached
+    else:
+        concretetable, uniquerows, oldsize = cached
+        if oldsize != callfamily.total_calltable_size:
+            raise TyperError("call table was unexpectedly extended")
+    return concretetable, uniquerows
+
+
 class FunctionsPBCRepr(MultiplePBCRepr):
     """Representation selected for a PBC of function(s)."""
 
@@ -76,50 +157,20 @@
         self.s_pbc = s_pbc
         self._function_signatures = None
         self.callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
-
-        # Build the complete call table with concrete low-level function
-        # objects.
-        concretetable = {}
-        uniquerows = {}
-        for shape, rows in self.callfamily.calltables.items():
-            for index, row in enumerate(rows):
-                concreterow = {}
-                key = frozendict()
-                last_sig = None
-                last_name = None
-                for funcdesc, graph in row.items():
-                    sig = (callparse.getrinputs(self.rtyper, graph),
-                           callparse.getrresult(self.rtyper, graph))
-                    if last_sig is None:
-                        last_sig = sig
-                        last_name = graph.name
-                    elif last_sig != sig:
-                        raise TyperError("normalization failed in call table:\n"
-                                         "graph %r sig %r\n"
-                                         "graph %r sig %r" % (
-                                             last_name, last_sig,
-                                             graph.name, sig))
-                    llfn = self.rtyper.getcallable(graph)
-                    concreterow[funcdesc] = llfn
-                    key[funcdesc] = self.rtyper.type_system_deref(llfn)
-                if key in uniquerows:
-                    attrname, concreterow = uniquerows[key]  # from the cache
-                else:
-                    attrname = 'variant%d' % len(uniquerows)
-                    uniquerows[key] = attrname, concreterow
-                concretetable[shape, index] = attrname, concreterow
-        self.concretetable = concretetable
-        self.uniquerows = uniquerows
-
         if len(s_pbc.descriptions) == 1 and not s_pbc.can_be_None:
             # a single function
             self.lowleveltype = Void
-        elif len(uniquerows) == 1:
-            [(attrname, row)] = uniquerows.values()
-            llfn = row.itervalues().next()
-            self.lowleveltype = typeOf(llfn)
         else:
-            XXX_later
+            concretetable, uniquerows = get_concrete_calltable(self.rtyper,
+                                                               self.callfamily)
+            self.concretetable = concretetable
+            self.uniquerows = uniquerows
+            if len(uniquerows) == 1:
+                row = uniquerows[0]
+                examplellfn = row.itervalues().next()
+                self.lowleveltype = typeOf(examplellfn)
+            else:
+                XXX_later
 
     def get_s_callable(self):
         return self.s_pbc
@@ -158,13 +209,13 @@
         funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
         llfns = {}
         found_anything = False
-        for attrname, row in self.uniquerows.values():
+        for row in self.uniquerows:
             if funcdesc in row:
                 llfn = row[funcdesc]
                 found_anything = True
             else:
                 llfn = null
-            llfns[attrname] = llfn
+            llfns[row.attrname] = llfn
         if not found_anything:
             raise TyperError("%r not in %r" % (value,
                                                self.s_pbc.descriptions))
@@ -182,8 +233,9 @@
             assert len(self.s_pbc.descriptions) == 1
                                       # lowleveltype wouldn't be Void otherwise
             funcdesc, = self.s_pbc.descriptions
-            attrname, row = self.concretetable[shape, index]
-            llfn = row[funcdesc]
+            row_of_one_graph = self.callfamily.calltables[shape][index]
+            graph = row_of_one_graph[funcdesc]
+            llfn = self.rtyper.getcallable(graph)
             return inputconst(typeOf(llfn), llfn)
         elif len(self.uniquerows) == 1:
             return v
@@ -195,10 +247,9 @@
         args = bk.build_args("simple_call", hop.args_s[1:])
         descs = self.s_pbc.descriptions.keys()
         row = description.FunctionDesc.row_to_consider(descs, args)
-        index =self.callfamily.calltable_lookup_row(args.rawshape(),
-                                                              row)
-        merged = self.callfamily.calltables[args.rawshape()][index]
-        anygraph = merged.itervalues().next()  # pick any witness
+        index = self.callfamily.calltable_lookup_row(args.rawshape(), row)
+        row_of_graphs = self.callfamily.calltables[args.rawshape()][index]
+        anygraph = row_of_graphs.itervalues().next()  # pick any witness
         vfn = hop.inputarg(self, arg=0)
         vlist = [self.convert_to_concrete_llfn(vfn, index, args.rawshape(),
                                                hop.llops)]

Modified: pypy/branch/somepbc-refactoring/pypy/rpython/rtyper.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/rpython/rtyper.py	(original)
+++ pypy/branch/somepbc-refactoring/pypy/rpython/rtyper.py	Wed Nov 23 20:02:20 2005
@@ -55,6 +55,7 @@
         self.class_reprs = {}
         self.instance_reprs = {}
         self.pbc_reprs = {}
+        self.concrete_calltables = {}
         self.class_pbc_attributes = {}
         self.typererrors = []
         self.typererror_count = 0



More information about the Pypy-commit mailing list