[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