[pypy-svn] r21124 - in pypy/dist/pypy/jit: . test

arigo at codespeak.net arigo at codespeak.net
Tue Dec 13 12:11:42 CET 2005


Author: arigo
Date: Tue Dec 13 12:11:40 2005
New Revision: 21124

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:
Try to propagate non-concrete constants, until they merge.


Modified: pypy/dist/pypy/jit/llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/llabstractinterp.py	(original)
+++ pypy/dist/pypy/jit/llabstractinterp.py	Tue Dec 13 12:11:40 2005
@@ -81,7 +81,11 @@
         return self.copy_v
 
     def getruntimevars(self, memo):
-        return [self.copy_v]
+        if (isinstance(self.copy_v, Variable) or
+            self not in memo.propagate_as_constants):
+            return [self.copy_v]
+        else:
+            return []   # we propagate this constant as a constant
 
     def maybe_get_constant(self):
         if isinstance(self.copy_v, Constant):
@@ -90,13 +94,23 @@
             return None
 
     def with_fresh_variables(self, memo):
-        return LLRuntimeValue(self.getconcretetype())
+        # don't use memo.seen here: shared variables must become distinct
+        if (isinstance(self.copy_v, Variable) or
+            self not in memo.propagate_as_constants):
+            return LLRuntimeValue(self.getconcretetype())
+        else:
+            return self   # we are allowed to propagate this constant
 
     def match(self, other, memo):
-        # Note: the meaning of match() is actually to see if calling
-        # with_fresh_variables() on both 'self' and 'other' would give the
-        # same result.  This is why any two LLRuntimeValues match each other.
-        return isinstance(other, LLRuntimeValue)
+        if not isinstance(other, LLRuntimeValue):
+            return False
+        if isinstance(self.copy_v, Variable):
+            return True
+        if self.copy_v == other.copy_v:
+            memo.propagate_as_constant[other] = True   # exact match
+        else:
+            memo.exact_match = False
+        return True
 
 ll_no_return_value = LLRuntimeValue(const(None, lltype.Void))
 
@@ -152,11 +166,11 @@
         self.fields[name] = a_value
 
     def with_fresh_variables(self, memo):
-        if self in memo:
-            return memo[self]    # already seen
+        if self in memo.seen:
+            return memo.seen[self]    # already seen
         else:
             result = virtualcontainer(self.T, self.a_length)
-            memo[self] = result
+            memo.seen[self] = result
             if self.parent is not None:
                 # build the parent first -- note that
                 # parent.with_fresh_variables() will pick up 'result' again,
@@ -221,8 +235,8 @@
 
     def getruntimevars(self, memo):
         result = []
-        if self not in memo:
-            memo[self] = True
+        if self not in memo.seen:
+            memo.seen[self] = True
             if self.parent is not None:
                 result.extend(self.parent.getruntimevars(memo))
             for name in self.names:
@@ -232,12 +246,14 @@
     def match(self, other, memo):
         if self.__class__ is not other.__class__:
             return False
-        if (False, self) in memo:
-            return other is memo[False, self]
-        if (True, other) in memo:
-            return self is memo[True, other]
-        memo[False, self] = other
-        memo[True, other] = self
+
+        if self in memo.self_alias:
+            return other is memo.self_alias[self]
+        if other in memo.other_alias:
+            return self is memo.other_alias[other]
+        memo.self_alias[self] = other
+        memo.other_alias[other] = self
+
         assert self.T == other.T
         if self.a_length is not None:
             if not self.a_length.match(other.a_length, memo):
@@ -370,6 +386,7 @@
 class LLBlockState(LLState):
     """Entry state of a block, as a combination of LLAbstractValues
     for its input arguments."""
+    propagate_as_constants = {}
 
     def localkey(self):
         return (self.origblock,)
@@ -396,13 +413,16 @@
 # ____________________________________________________________
 
 class Policy(object):
-    def __init__(self, inlining=False):
+    def __init__(self, inlining=False, const_propagate=False):
         self.inlining = inlining
+        self.const_propagate = const_propagate
+
+best_policy = Policy(inlining=True, const_propagate=True)
 
 
 class LLAbstractInterp(object):
 
-    def __init__(self, policy=Policy()):
+    def __init__(self, policy=best_policy):
         self.graphs = []
         self.graphstates = {}     # {origgraph: {BlockState: GraphState}}
         self.pendingstates = {}   # {Link-or-GraphState: next-BlockState}
@@ -441,7 +461,8 @@
     def schedule(self, inputstate):
         #print "SCHEDULE", args_a, origblock
         state = self.schedule_getstate(inputstate)
-        args_v = inputstate.getruntimevars({})
+        memo = VarMemo(state.propagate_as_constants)
+        args_v = inputstate.getruntimevars(memo)
         newlink = Link(args_v, None)
         self.pendingstates[newlink] = state
         return newlink
@@ -451,13 +472,24 @@
         pendingstates = self.blocks.setdefault(inputstate.key(), [])
         # try to match the input state with an existing one
         for state in pendingstates:
-            if state.match(inputstate, {}):
+            memo = MatchMemo()
+            if state.match(inputstate, memo):
                 # already matched
-                return state
-        else:
-            # cache and return this new state
-            pendingstates.append(inputstate)
-            return inputstate
+                if memo.exact_match:
+                    return state    # exact match
+                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
+                inputstate.propagate_as_constants = memo.propagate_as_constants
+                break
+        else:
+            if self.policy.const_propagate:
+                inputstate.propagate_as_constants = ALL
+        # cache and return this new state
+        pendingstates.append(inputstate)
+        return inputstate
 
 
 class GraphState(object):
@@ -618,8 +650,10 @@
 
     def __init__(self, interp, initialstate):
         self.interp = interp
-        self.runningstate = initialstate.with_fresh_variables({})
-        self.newinputargs = self.runningstate.getruntimevars({})
+        memo = VarMemo(initialstate.propagate_as_constants)
+        self.runningstate = initialstate.with_fresh_variables(memo)
+        memo = VarMemo(initialstate.propagate_as_constants)
+        self.newinputargs = self.runningstate.getruntimevars(memo)
         # {Variables-of-origblock: a_value}
         self.bindings = self.runningstate.getbindings()
         self.residual_operations = []
@@ -885,7 +919,7 @@
 
     def op_keepalive(self, op, a_ptr):
         if isinstance(a_ptr, LLVirtualStruct):
-            for v in a_ptr.getruntimevars({}):
+            for v in a_ptr.getruntimevars(VarMemo()):
                 if isinstance(v, Variable) and not v.concretetype._is_atomic():
                     op = SpaceOperation('keepalive', [v], newvar(lltype.Void))
                     print 'virtual:', op
@@ -898,6 +932,23 @@
     def __init__(self, link):
         self.link = link
 
+class MatchMemo(object):
+    def __init__(self):
+        self.exact_match = True
+        self.propagate_as_constant = {}
+        self.self_alias = {}
+        self.other_alias = {}
+
+class VarMemo(object):
+    def __init__(self, propagate_as_constants={}):
+        self.seen = {}
+        self.propagate_as_constants = propagate_as_constants
+
+class ALL(object):
+    def __contains__(self, other):
+        return True
+ALL = ALL()
+
 
 def live_variables(block, position):
     # return a list of all variables alive in the block at the beginning of

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	Tue Dec 13 12:11:40 2005
@@ -3,7 +3,7 @@
 import py
 from pypy.translator.translator import TranslationContext
 from pypy.jit import tl
-from pypy.jit.llabstractinterp import LLAbstractInterp, Policy
+from pypy.jit.llabstractinterp import LLAbstractInterp
 from pypy.rpython.rstr import string_repr
 from pypy.rpython.llinterp import LLInterpreter
 #from pypy.translator.backendopt import inline
@@ -22,7 +22,7 @@
     
 
 def jit_tl(code):
-    interp = LLAbstractInterp(Policy(inlining=True))
+    interp = LLAbstractInterp()
     hints = {0: string_repr.convert_const(code),
              1: 0}
     graph2 = interp.eval(graph1, hints)

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 12:11:40 2005
@@ -62,6 +62,7 @@
     return graph2, insns
 
 P_INLINE = Policy(inlining=True)
+P_CONST_INLINE = Policy(inlining=True, const_propagate=True)
 
 
 def test_simple():
@@ -313,3 +314,11 @@
         return ll2(x, y - z)
     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 == {}



More information about the Pypy-commit mailing list