[pypy-svn] r21267 - in pypy/dist/pypy/jit: . test
arigo at codespeak.net
arigo at codespeak.net
Sun Dec 18 13:28:18 CET 2005
Author: arigo
Date: Sun Dec 18 13:28:16 2005
New Revision: 21267
Modified:
pypy/dist/pypy/jit/llabstractinterp.py
pypy/dist/pypy/jit/test/test_jit_tl.py
pypy/dist/pypy/jit/test/test_llabstractinterp.py
Log:
Reintroduce something like the const_propagate policy. It doesn't look too
bad, and the tests so far pass, but there is a flaw in here...
Modified: pypy/dist/pypy/jit/llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/llabstractinterp.py (original)
+++ pypy/dist/pypy/jit/llabstractinterp.py Sun Dec 18 13:28:16 2005
@@ -57,8 +57,18 @@
class LLRuntimeValue(LLAbstractValue):
- origin = None
- fixed = False
+
+ origin = None # list of LLRuntimeValues attached to a saved state:
+ # the sources that did or could allow 'self' to be
+ # computed as a constant
+
+ becomes = "var" # only meaningful on LLRuntimeValues attached to a
+ # saved state. Describes what this LLRuntimeValue will
+ # become in the next block:
+ # "var" - becomes a Variable in the next block
+ # "single" - only one Constant seen so far, so
+ # for now it can stay a Constant
+ # "fixed" - forced by hint() to stay a Constant
def __init__(self, orig_v):
if isinstance(orig_v, Variable):
@@ -67,6 +77,8 @@
elif isinstance(orig_v, Constant):
# we can share the Constant()
self.copy_v = orig_v
+ self.origin = []
+ self.becomes = "single"
elif isinstance(orig_v, lltype.LowLevelType):
# hackish interface :-( we accept a type too
self.copy_v = newvar(orig_v)
@@ -83,10 +95,17 @@
return self.copy_v
def getruntimevars(self, memo):
- if memo.get_fixed_flags:
- return [self.fixed]
- else:
+ if memo.key is None:
return [self.copy_v]
+ else:
+ c = memo.key.next()
+ if self.becomes == "var":
+ return [None]
+ else:
+ assert isinstance(c, Constant), (
+ "unexpected Variable %r reaching a %r input arg" %
+ (c, self.becomes))
+ return [c]
def maybe_get_constant(self):
if isinstance(self.copy_v, Constant):
@@ -96,16 +115,16 @@
def with_fresh_variables(self, memo):
# don't use memo.seen here: shared variables must become distinct
- if memo.key is not None:
- c = memo.key.next()
- if c is not None:
- return LLRuntimeValue(c)
- result = LLRuntimeValue(self.getconcretetype())
+ c = memo.key and memo.key.next()
+ if c is not None: # allowed to propagate as a Constant?
+ result = LLRuntimeValue(c)
+ else:
+ result = LLRuntimeValue(self.getconcretetype())
result.origin = [self]
return result
def match(self, other, memo):
- memo.dependencies.append((self, other, self.fixed))
+ memo.dependencies.append((self, other))
return isinstance(other, LLRuntimeValue)
ll_no_return_value = LLRuntimeValue(const(None, lltype.Void))
@@ -417,13 +436,14 @@
# ____________________________________________________________
class Policy(object):
- def __init__(self, inlining=False,
+ def __init__(self, inlining=False, const_propagate=False,
concrete_propagate=True, concrete_args=True):
self.inlining = inlining
+ self.const_propagate = const_propagate
self.concrete_propagate = concrete_propagate
self.concrete_args = concrete_args
-best_policy = Policy(inlining=True, concrete_args=False)
+best_policy = Policy(inlining=True, const_propagate=True)
class LLAbstractInterp(object):
@@ -484,15 +504,26 @@
if state.match(inputstate, memo):
# already matched
must_restart = False
- for statevar, inputvar, fixed in memo.dependencies:
- if fixed:
+ for statevar, inputvar in memo.dependencies:
+ if statevar.becomes == "single":
+ # the saved state only records one possible Constant
+ # incoming value so far. Are we seeing a different
+ # Constant, or even a Variable?
+ if inputvar.copy_v != statevar.copy_v:
+ statevar.becomes = "var"
+ must_restart = True
+ elif statevar.becomes == "fixed":
+ # the saved state says that this new incoming
+ # variable must be forced to a constant
must_restart |= self.hint_needs_constant(inputvar)
if must_restart:
raise RestartCompleting
- for statevar, inputvar, fixed in memo.dependencies:
- if statevar.origin is None:
- statevar.origin = []
- statevar.origin.append(inputvar)
+ # The new inputstate is merged into the existing saved state.
+ # Record this inputstate's variables in the possible origins
+ # of the saved state's variables.
+ for statevar, inputvar in memo.dependencies:
+ if statevar.origin is not None:
+ statevar.origin.append(inputvar)
return state
else:
# cache and return this new state
@@ -500,23 +531,28 @@
return inputstate
def hint_needs_constant(self, a):
- if a.maybe_get_constant() is not None:
- return False
+ # Force the given LLRuntimeValue to be a fixed constant.
+ must_restart = False
fix_me = [a]
while fix_me:
a = fix_me.pop()
- if not a.origin:
+ assert isinstance(a, LLRuntimeValue)
+ if a.becomes == "fixed":
+ continue # already fixed
+ print 'fixing:', a
+ if a.becomes == "var":
+ must_restart = True # this Var is now fixed
+ # (no need to restart if a.becomes was "single")
+ a.becomes = "fixed"
+ if a.origin:
+ fix_me.extend(a.origin)
+ elif a.maybe_get_constant() is None:
+ # a Variable with no recorded origin
raise Exception("hint() failed: cannot trace the variable %r "
"back to a link where it was a constant" % (a,))
- for a_origin in a.origin:
- # 'a_origin' is a LLRuntimeValue attached to a saved state
- assert isinstance(a_origin, LLRuntimeValue)
- if not a_origin.fixed:
- print 'fixing:', a_origin
- a_origin.fixed = True
- if a_origin.maybe_get_constant() is None:
- fix_me.append(a_origin)
- return True
+ assert self.policy.const_propagate, (
+ "hint() can only be used with a policy of const_propagate=True")
+ return must_restart
class GraphState(object):
@@ -569,17 +605,10 @@
while pending:
next = pending.pop()
state = interp.pendingstates[next]
- fixed_flags = state.getruntimevars(VarMemo(get_fixed_flags=True))
- key = []
- for fixed, c in zip(fixed_flags, next.args):
- if fixed:
- assert isinstance(c, Constant), (
- "unexpected Variable %r reaching a fixed input arg" %
- (c,))
- key.append(c)
- else:
- key.append(None)
- key = tuple(key)
+ if interp.policy.const_propagate:
+ key = tuple(state.getruntimevars(VarMemo(next.args)))
+ else:
+ key = None
if key not in state.copyblocks:
self.flowin(state, key)
block = state.copyblocks[key]
@@ -626,14 +655,15 @@
newexitswitch = None
# debugging print
arglist = []
- for v1, v2, k in zip(state.getruntimevars(VarMemo()),
- builder.runningstate.getruntimevars(VarMemo()),
- key):
- if k is None:
- assert isinstance(v2, Variable)
- else:
- assert v2 == k
- arglist.append('%s => %s' % (v1, v2))
+ if key:
+ for v1, v2, k in zip(state.getruntimevars(VarMemo()),
+ builder.runningstate.getruntimevars(VarMemo()),
+ key):
+ if k is None:
+ assert isinstance(v2, Variable)
+ else:
+ assert v2 == k
+ arglist.append('%s => %s' % (v1, v2))
print
print '--> %s [%s]' % (origblock, ', '.join(arglist))
for op in origblock.operations:
@@ -718,7 +748,7 @@
def __init__(self, interp, initialstate, key):
self.interp = interp
- memo = VarMemo(iter(key))
+ memo = VarMemo(key)
self.runningstate = initialstate.with_fresh_variables(memo)
self.newinputargs = self.runningstate.getruntimevars(VarMemo())
# {Variables-of-origblock: a_value}
@@ -767,7 +797,9 @@
if any_concrete and self.interp.policy.concrete_propagate:
return LLConcreteValue(concreteresult)
else:
- return LLRuntimeValue(const(concreteresult))
+ a_result = LLRuntimeValue(const(concreteresult))
+ self.record_origin(a_result, args_a)
+ return a_result
def residual(self, opname, args_a, a_result):
v_result = a_result.forcevarorconst(self)
@@ -796,7 +828,7 @@
def record_origin(self, a_result, args_a):
origin = []
for a in args_a:
- if a.maybe_get_constant() is not None:
+ if isinstance(a, LLConcreteValue):
continue
if not isinstance(a, LLRuntimeValue) or a.origin is None:
return
@@ -1044,10 +1076,12 @@
self.other_alias = {}
class VarMemo(object):
- def __init__(self, key=None, get_fixed_flags=False):
+ def __init__(self, key=None):
self.seen = {}
- self.key = key
- self.get_fixed_flags = get_fixed_flags
+ if key is not None:
+ self.key = iter(key)
+ else:
+ self.key = None
def live_variables(block, position):
Modified: pypy/dist/pypy/jit/test/test_jit_tl.py
==============================================================================
--- pypy/dist/pypy/jit/test/test_jit_tl.py (original)
+++ pypy/dist/pypy/jit/test/test_jit_tl.py Sun Dec 18 13:28:16 2005
@@ -32,7 +32,7 @@
assert result1 == result2
- interp.graphs[0].show()
+ #interp.graphs[0].show()
def run_jit(code):
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 Sun Dec 18 13:28:16 2005
@@ -62,7 +62,8 @@
return graph2, insns
P_INLINE = Policy(inlining=True)
-P_HINT_DRIVEN = Policy(inlining=True, concrete_args=False)
+P_CONST_INLINE = Policy(inlining=True, const_propagate=True)
+P_HINT_DRIVEN = Policy(inlining=True, const_propagate=True, concrete_args=False)
def test_simple():
@@ -315,13 +316,13 @@
graph2, insns = abstrinterp(ll1, [3, 4, 5], [1, 2], policy=P_INLINE)
assert insns == {'int_add': 1}
-##def test_const_propagate():
-## def ll_add(x, y):
-## return x + y
-## def ll1(x):
-## return ll_add(x, 42)
-## graph2, insns = abstrinterp(ll1, [3], [0], policy=P_CONST_INLINE)
-## assert insns == {}
+def test_const_propagate():
+ def ll_add(x, y):
+ return x + y
+ def ll1(x):
+ 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):
@@ -331,7 +332,7 @@
i += 1
result *= i
return result
- graph2, insns = abstrinterp(ll_factorial, [7], [], policy=P_INLINE)
+ graph2, insns = abstrinterp(ll_factorial, [7], [], policy=P_CONST_INLINE)
assert insns == {'int_lt': 1, 'int_add': 1, 'int_mul': 1}
def test_hint():
@@ -358,3 +359,32 @@
graph2, insns = abstrinterp(ll_interp, [bytecode], [0],
policy=P_HINT_DRIVEN)
assert insns == {'int_add': 4, 'int_lt': 1}
+
+def test_hint_across_call():
+ from pypy.rpython.objectmodel import hint
+ A = lltype.GcArray(lltype.Char, hints={'immutable': True})
+ def ll_length(a):
+ return len(a)
+ def ll_getitem(a, i):
+ return a[i]
+ def ll_interp(code):
+ accum = 0
+ pc = 0
+ while pc < ll_length(code):
+ opcode = hint(ll_getitem(code, pc), concrete=True)
+ pc += 1
+ if opcode == 'A':
+ accum += 6
+ elif opcode == 'B':
+ if accum < 20:
+ pc = 0
+ return accum
+ bytecode = lltype.malloc(A, 5)
+ bytecode[0] = 'A'
+ bytecode[1] = 'A'
+ bytecode[2] = 'A'
+ bytecode[3] = 'B'
+ bytecode[4] = 'A'
+ graph2, insns = abstrinterp(ll_interp, [bytecode], [0],
+ policy=P_HINT_DRIVEN)
+ assert insns == {'int_add': 4, 'int_lt': 1}
More information about the Pypy-commit
mailing list