[pypy-svn] r21127 - in pypy/dist/pypy/jit: . test
arigo at codespeak.net
arigo at codespeak.net
Tue Dec 13 13:04:07 CET 2005
Author: arigo
Date: Tue Dec 13 13:04:05 2005
New Revision: 21127
Modified:
pypy/dist/pypy/jit/llabstractinterp.py
pypy/dist/pypy/jit/test/test_llabstractinterp.py
Log:
More on eager constant propagation: don't be too eager :-)
This fixes the merging detection, and adds a second phase
after a graph is complete to "compactify" it by linking
blocks for old states directly to their generalized counterpart.
Modified: pypy/dist/pypy/jit/llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/llabstractinterp.py (original)
+++ pypy/dist/pypy/jit/llabstractinterp.py Tue Dec 13 13:04:05 2005
@@ -107,7 +107,7 @@
if isinstance(self.copy_v, Variable):
return True
if self.copy_v == other.copy_v:
- memo.propagate_as_constant[other] = True # exact match
+ memo.propagate_as_constants[other] = True # exact match
else:
memo.exact_match = False
return True
@@ -316,6 +316,7 @@
class LLState(LLAbstractValue):
"""Entry state of a block, as a combination of LLAbstractValues
for its input arguments. Abstract base class."""
+ generalized_by = None
def __init__(self, a_back, args_a, origblock):
self.a_back = a_back
@@ -377,7 +378,15 @@
def resolveblock(self, newblock):
#print "RESOLVING BLOCK", newblock
- self.copyblock = newblock
+ if self.copyblock is not None:
+ # uncommon case: must patch the existing Block
+ assert len(self.copyblock.inputargs) == len(newblock.inputargs)
+ self.copyblock.inputargs = newblock.inputargs
+ self.copyblock.operations = newblock.operations
+ self.copyblock.exitswitch = newblock.exitswitch
+ self.copyblock.recloseblock(*newblock.exits)
+ else:
+ self.copyblock = newblock
def getbindings(self):
return dict(zip(self.getlivevars(), self.args_a))
@@ -471,7 +480,7 @@
# NOTA BENE: copyblocks can get shared between different copygraphs!
pendingstates = self.blocks.setdefault(inputstate.key(), [])
# try to match the input state with an existing one
- for state in pendingstates:
+ for i, state in enumerate(pendingstates):
memo = MatchMemo()
if state.match(inputstate, memo):
# already matched
@@ -480,16 +489,18 @@
if not self.policy.const_propagate:
return state # all constants will be generalized anyway
# partial match: in the old state, some constants need to
- # be turned into variables. XXX patch oldstate.block to point
- # to the new state, as in the flow object space
+ # be turned into variables.
inputstate.propagate_as_constants = memo.propagate_as_constants
- break
+ # The generalized state replaces the existing one.
+ pendingstates[i] = inputstate
+ state.generalized_by = inputstate
+ return inputstate
else:
+ # cache and return this new state
if self.policy.const_propagate:
inputstate.propagate_as_constants = ALL
- # cache and return this new state
- pendingstates.append(inputstate)
- return inputstate
+ pendingstates.append(inputstate)
+ return inputstate
class GraphState(object):
@@ -534,21 +545,25 @@
self.flowin(state)
next.settarget(state.copyblock)
for link in state.copyblock.exits:
- if link not in seen:
- seen[link] = True
- if link.target is None or link.target.operations != ():
+ if link.target is None or link.target.operations != ():
+ if link not in seen:
+ seen[link] = True
pending.append(link)
+ else:
+ # link.target is a return or except block; make sure
+ # that it is really the one from 'graph' -- by patching
+ # 'graph' if necessary.
+ if len(link.target.inputargs) == 1:
+ self.a_return = state.args_a[0]
+ graph.returnblock = link.target
+ elif len(link.target.inputargs) == 2:
+ graph.exceptblock = link.target
else:
- # link.target is a return or except block; make sure
- # that it is really the one from 'graph' -- by patching
- # 'graph' if necessary.
- if len(link.target.inputargs) == 1:
- self.a_return = state.args_a[0]
- graph.returnblock = link.target
- elif len(link.target.inputargs) == 2:
- graph.exceptblock = link.target
- else:
- raise Exception("uh?")
+ raise Exception("uh?")
+
+ if interp.policy.const_propagate:
+ self.compactify(seen)
+
# the graph should be complete now; sanity-check
try:
checkgraph(graph)
@@ -563,6 +578,25 @@
join_blocks(graph)
self.state = "after"
+ def compactify(self, links):
+ # remove the parts of the graph that use constants that were later
+ # generalized
+ interp = self.interp
+ for link in links:
+ oldstate = interp.pendingstates[link]
+ if oldstate.generalized_by is not None:
+ newstate = oldstate.generalized_by
+ while newstate.generalized_by:
+ newstate = newstate.generalized_by
+ # Patch oldstate.block to point to the new state,
+ # as in the flow object space
+ builder = BlockBuilder(self, oldstate)
+ memo = VarMemo(newstate.propagate_as_constants)
+ args_v = builder.runningstate.getruntimevars(memo)
+ oldlink = Link(args_v, newstate.copyblock)
+ oldblock = builder.buildblock(None, [oldlink])
+ oldstate.resolveblock(oldblock)
+
def flowin(self, state):
# flow in the block
assert isinstance(state, LLBlockState)
@@ -935,7 +969,7 @@
class MatchMemo(object):
def __init__(self):
self.exact_match = True
- self.propagate_as_constant = {}
+ self.propagate_as_constants = {}
self.self_alias = {}
self.other_alias = {}
Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original)
+++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Tue Dec 13 13:04:05 2005
@@ -322,3 +322,14 @@
return ll_add(x, 42)
graph2, insns = abstrinterp(ll1, [3], [0], policy=P_CONST_INLINE)
assert insns == {}
+
+def test_dont_unroll_loop():
+ def ll_factorial(n):
+ i = 1
+ result = 1
+ while i < n:
+ i += 1
+ result *= i
+ return result
+ graph2, insns = abstrinterp(ll_factorial, [7], [], policy=P_CONST_INLINE)
+ assert insns == {'int_lt': 1, 'int_add': 1, 'int_mul': 1}
More information about the Pypy-commit
mailing list