[pypy-svn] r25610 - in pypy/dist/pypy: objspace/flow translator/backendopt translator/backendopt/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Sun Apr 9 12:08:20 CEST 2006
Author: cfbolz
Date: Sun Apr 9 12:08:15 2006
New Revision: 25610
Added:
pypy/dist/pypy/translator/backendopt/mallocprediction.py
pypy/dist/pypy/translator/backendopt/test/test_mallocprediction.py
Modified:
pypy/dist/pypy/objspace/flow/model.py
pypy/dist/pypy/translator/backendopt/escape.py
pypy/dist/pypy/translator/backendopt/inline.py
Log:
try to find out calls that are interesting to inline because doing that will
probably enable malloc removal.
Modified: pypy/dist/pypy/objspace/flow/model.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/model.py (original)
+++ pypy/dist/pypy/objspace/flow/model.py Sun Apr 9 12:08:15 2006
@@ -98,6 +98,11 @@
seen[block] = True
stack += block.exits[::-1]
+ def iterblockops(self):
+ for block in self.iterblocks():
+ for op in block.operations:
+ yield block, op
+
def show(self):
from pypy.translator.tool.graphpage import SingleGraphPage
SingleGraphPage(self).display()
Modified: pypy/dist/pypy/translator/backendopt/escape.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/escape.py (original)
+++ pypy/dist/pypy/translator/backendopt/escape.py Sun Apr 9 12:08:15 2006
@@ -369,25 +369,25 @@
adi.complete()
for graph in t.graphs:
loop_blocks = support.find_loop_blocks(graph)
- for block in graph.iterblocks():
- for op in block.operations:
- if op.opname == 'malloc':
- STRUCT = op.args[0].value
- # must not remove mallocs of structures that have a RTTI with a destructor
- try:
- destr_ptr = lltype.getRuntimeTypeInfo(STRUCT)._obj.destructor_funcptr
- if destr_ptr:
- continue
- except (ValueError, AttributeError), e:
- pass
- varstate = adi.getstate(op.result)
- assert len(varstate.creation_points) == 1
- crep = varstate.creation_points.keys()[0]
- if not crep.escapes:
- if block not in loop_blocks:
- print "moving object from heap to stack %s in %s" % (op, graph.name)
- op.opname = 'flavored_malloc'
- op.args.insert(0, inputconst(lltype.Void, 'stack'))
- else:
- print "%s in %s is a non-escaping malloc in a loop" % (op, graph.name)
+ for block, op in graph.iterblockops():
+ if op.opname == 'malloc':
+ STRUCT = op.args[0].value
+ # must not remove mallocs of structures that have a RTTI with a destructor
+ try:
+ destr_ptr = lltype.getRuntimeTypeInfo(STRUCT)._obj.destructor_funcptr
+ if destr_ptr:
+ continue
+ except (ValueError, AttributeError), e:
+ pass
+ varstate = adi.getstate(op.result)
+ assert len(varstate.creation_points) == 1
+ crep = varstate.creation_points.keys()[0]
+ if not crep.escapes:
+ if block not in loop_blocks:
+ print "moving object from heap to stack %s in %s" % (op, graph.name)
+ op.opname = 'flavored_malloc'
+ op.args.insert(0, inputconst(lltype.Void, 'stack'))
+ else:
+ print "%s in %s is a non-escaping malloc in a loop" % (op, graph.name)
+
Modified: pypy/dist/pypy/translator/backendopt/inline.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/inline.py (original)
+++ pypy/dist/pypy/translator/backendopt/inline.py Sun Apr 9 12:08:15 2006
@@ -520,12 +520,14 @@
return result
-def auto_inlining(translator, threshold=1):
+def auto_inlining(translator, threshold=1, callgraph=None):
from heapq import heappush, heappop, heapreplace
threshold *= BASE_INLINE_THRESHOLD
callers = {} # {graph: {graphs-that-call-it}}
callees = {} # {graph: {graphs-that-it-calls}}
- for graph1, graph2 in static_callers(translator, ignore_primitives=True):
+ if callgraph is None:
+ callgraph = static_callers(translator, ignore_primitives=True)
+ for graph1, graph2 in callgraph:
callers.setdefault(graph2, {})[graph1] = True
callees.setdefault(graph1, {})[graph2] = True
heap = [(0.0, -len(callers[graph]), graph) for graph in callers]
Added: pypy/dist/pypy/translator/backendopt/mallocprediction.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/backendopt/mallocprediction.py Sun Apr 9 12:08:15 2006
@@ -0,0 +1,116 @@
+from pypy.translator.backendopt.escape import AbstractDataFlowInterpreter
+from pypy.translator.backendopt.malloc import remove_simple_mallocs
+from pypy.translator.backendopt.inline import auto_inlining
+from pypy.rpython.lltypesystem import lltype
+from pypy.translator.simplify import get_graph
+
+def find_malloc_creps(graph, adi, translator):
+ # mapping from malloc creation point to graphs that it flows into
+ malloc_creps = {}
+ # find all mallocs that don't escape
+ for block, op in graph.iterblockops():
+ if op.opname == 'malloc':
+ STRUCT = op.args[0].value
+ # must not remove mallocs of structures that have a RTTI with a destructor
+ try:
+ destr_ptr = lltype.getRuntimeTypeInfo(
+ STRUCT)._obj.destructor_funcptr
+ if destr_ptr:
+ continue
+ except (ValueError, AttributeError), e:
+ pass
+ varstate = adi.getstate(op.result)
+ assert len(varstate.creation_points) == 1
+ crep = varstate.creation_points.keys()[0]
+ if not crep.escapes:
+ malloc_creps[crep] = {}
+ return malloc_creps
+
+def find_calls_where_creps_go(interesting_creps, graph, adi,
+ translator, seen):
+ print "find_calls_where_creps_go", interesting_creps, graph.name
+ print seen
+ # drop creps that are merged with another creation point
+ for block in graph.iterblocks():
+ for var in block.getvariables():
+ varstate = adi.getstate(var)
+ if varstate is None:
+ continue
+ for crep in varstate.creation_points:
+ if crep in interesting_creps:
+ if len(varstate.creation_points) != 1:
+ del interesting_creps[crep]
+ break
+
+ # drop creps that are passed into an indirect_call
+ for block, op in graph.iterblockops():
+ if not interesting_creps:
+ return
+ if op.opname == "indirect_call":
+ for var in op.args[:-1]:
+ varstate = adi.getstate(var)
+ for crep in varstate.creation_points:
+ if crep in interesting_creps:
+ del interesting_creps[crep]
+ elif op.opname == "direct_call":
+ print op, interesting_creps
+ called_graph = get_graph(op.args[0], translator)
+ if called_graph is None:
+ del interesting_creps[crep]
+ print "graph not found"
+ continue
+ interesting = {}
+ for i, var in enumerate(op.args[1:]):
+ print i, var,
+ varstate = adi.getstate(var)
+ if varstate is None:
+ print "no varstate"
+ continue
+ if len(varstate.creation_points) == 1:
+ crep = varstate.creation_points.keys()[0]
+ if crep not in interesting_creps:
+ print "not interesting"
+ continue
+ if (called_graph, i) in seen:
+ seen[(called_graph, i)][graph] = True
+ print "seen already"
+ else:
+ print "taking", crep
+ seen[(called_graph, i)] = {graph: True}
+ arg = called_graph.startblock.inputargs[i]
+ argstate = adi.getstate(arg)
+ argcrep = [c for c in argstate.creation_points
+ if c.creation_method == "arg"][0]
+ interesting[argcrep] = True
+ print interesting
+ if interesting:
+ find_calls_where_creps_go(interesting, called_graph,
+ adi, translator, seen)
+ return interesting_creps
+
+def find_malloc_removal_candidates(t):
+ adi = AbstractDataFlowInterpreter(t)
+ for graph in t.graphs:
+ if graph.startblock not in adi.flown_blocks:
+ adi.schedule_function(graph)
+ adi.complete()
+ caller_candidates = {}
+ seen = {}
+ for graph in t.graphs:
+ creps = find_malloc_creps(graph, adi, t)
+ print "malloc creps", creps
+ if creps:
+ find_calls_where_creps_go(creps, graph, adi, t, seen)
+ if creps:
+ caller_candidates[graph] = True
+ callgraph = []
+ for (called_graph, i), callers in seen.iteritems():
+ for caller in callers:
+ callgraph.append((caller, called_graph))
+ return callgraph, caller_candidates
+
+def inline_and_remove(t, threshold=1):
+ callgraph, caller_candidates = find_malloc_removal_candidates(t)
+ auto_inlining(t, threshold, callgraph)
+ for graph in caller_candidates:
+ remove_simple_mallocs(graph)
Added: pypy/dist/pypy/translator/backendopt/test/test_mallocprediction.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/backendopt/test/test_mallocprediction.py Sun Apr 9 12:08:15 2006
@@ -0,0 +1,86 @@
+import py
+from pypy.translator.translator import TranslationContext
+from pypy.translator.backendopt.inline import inline_function
+from pypy.translator.backendopt.all import backend_optimizations
+from pypy.translator.translator import TranslationContext, graphof
+from pypy.rpython.llinterp import LLInterpreter
+from pypy.objspace.flow.model import checkgraph, flatten, Block
+from pypy.conftest import option
+
+from pypy.translator.backendopt.mallocprediction import *
+
+def compile(fn, signature):
+ t = TranslationContext()
+ t.buildannotator().build_types(fn, signature)
+ t.buildrtyper().specialize()
+ graph = graphof(t, fn)
+ if option.view:
+ t.view()
+ return t, graph
+
+
+def check_inlining(t, graph, args, result):
+ callgraph, caller_candidates = find_malloc_removal_candidates(t)
+ nice_callgraph = {}
+ for caller, callee in callgraph:
+ nice_callgraph.setdefault(caller, {})[callee] = True
+ inline_and_remove(t)
+ if option.view:
+ t.view()
+ interp = LLInterpreter(t.rtyper)
+ res = interp.eval_graph(graph, args)
+ assert res == result
+ return nice_callgraph, caller_candidates
+
+def test_fn():
+ class A:
+ pass
+ class B(A):
+ pass
+ def g(a, b, i):
+ a.b = b
+ b.i = i
+ return a.b.i
+ def h(x):
+ return x + 42
+ def fn(i):
+ a = A()
+ b = B()
+ x = h(i)
+ return g(a, b, x)
+ t, graph = compile(fn, [int])
+ callgraph, caller_candidates = check_inlining(t, graph, [0], 42)
+ assert caller_candidates == {graph: True}
+ assert len(callgraph) == 1
+ ggraph = graphof(t, g)
+ assert callgraph[graph] == {ggraph: True}
+
+def test_multiple_calls():
+ class A:
+ pass
+ class B(A):
+ pass
+ def g2(b, i):
+ b.i = h(i)
+ def g1(a, b, i):
+ a.b = b
+ g2(b, h(i))
+ return a.b.i
+ def h(x):
+ return x + 42
+ def fn(i):
+ a = A()
+ b = B()
+ x = h(i)
+ return g1(a, b, x)
+ t, graph = compile(fn, [int])
+ callgraph, caller_candidates = check_inlining(t, graph, [0], 3 * 42)
+ print callgraph
+ assert caller_candidates == {graph: True}
+ assert len(callgraph) == 1
+ g1graph = graphof(t, g1)
+ g2graph = graphof(t, g2)
+ assert callgraph[graph] == {g1graph: True}
+ callgraph, caller_candidates = check_inlining(t, graph, [0], 3 * 42)
+ assert callgraph[graph] == {g2graph: True}
+
More information about the Pypy-commit
mailing list