[pypy-svn] r32501 - in pypy/branch/timeshift-refactoring/pypy/translator/backendopt: . test

arigo at codespeak.net arigo at codespeak.net
Tue Sep 19 16:57:43 CEST 2006


Author: arigo
Date: Tue Sep 19 16:57:37 2006
New Revision: 32501

Modified:
   pypy/branch/timeshift-refactoring/pypy/translator/backendopt/ssa.py
   pypy/branch/timeshift-refactoring/pypy/translator/backendopt/test/test_ssa.py
Log:
(arre, arigo)

A possibly useful tool for graph construction and transformation.
It allows us to build a few blocks without worrying about passing
variables along links and renaming them *at all*, and then goes
along and fixes the blocks.  More precisely, it's an SSA to SSI
transformation.


Modified: pypy/branch/timeshift-refactoring/pypy/translator/backendopt/ssa.py
==============================================================================
--- pypy/branch/timeshift-refactoring/pypy/translator/backendopt/ssa.py	(original)
+++ pypy/branch/timeshift-refactoring/pypy/translator/backendopt/ssa.py	Tue Sep 19 16:57:37 2006
@@ -16,9 +16,7 @@
         # [Block, blockvar, linkvar, linkvar, linkvar...]
         opportunities = []
         opportunities_with_const = []
-        for block, links in mkentrymap(graph).items():
-            if block is graph.startblock:
-                continue
+        for block, links in mkinsideentrymap(graph).items():
             assert links
             for n, inputvar in enumerate(block.inputargs):
                 vars = [block, inputvar]
@@ -124,3 +122,92 @@
         vct = [getattr(v, 'concretetype', None) for v in vlist]
         assert vct == vct[:1] * len(vct), (
             "variables called %s have mixed concretetypes: %r" % (vname, vct))
+
+# ____________________________________________________________
+
+def mkinsideentrymap(graph_or_blocks):
+    # graph_or_blocks can be a full FunctionGraph, or a mapping
+    # {block: reachable-from-outside-flag}.
+    if isinstance(graph_or_blocks, dict):
+        blocks = graph_or_blocks
+        entrymap = {}
+        for block in blocks:
+            for link in block.exits:
+                if link.target in blocks and not blocks[link.target]:
+                    entrymap.setdefault(link.target, []).append(link)
+        return entrymap
+    else:
+        graph = graph_or_blocks
+        entrymap = mkentrymap(graph)
+        del entrymap[graph.startblock]
+        return entrymap
+
+def variables_created_in(block):
+    result = {}
+    for v in block.inputargs:
+        result[v] = True
+    for op in block.operations:
+        result[op.result] = True
+    return result
+
+
+def SSA_to_SSI(blocks, annotator=None):
+    """Turn a number of blocks belonging to a flow graph into valid (i.e. SSI)
+    form, assuming that they are only in SSA form (i.e. they can use each
+    other's variables directly, without having to pass and rename them along
+    links).
+
+    'blocks' is a mapping {block: reachable-from-outside-flag}.
+    """
+    from pypy.translator.unsimplify import copyvar
+
+    entrymap = mkinsideentrymap(blocks)
+    variable_families = DataFlowFamilyBuilder(blocks).get_variable_families()
+
+    pending = []     # list of (block, var-used-but-not-defined)
+
+    for block in blocks:
+        variables_created = variables_created_in(block)
+        variables_used = {}
+        for op in block.operations:
+            for v in op.args:
+                if isinstance(v, Variable):
+                    variables_used[v] = True
+        if isinstance(block.exitswitch, Variable):
+            variables_used[v] = True
+        for link in block.exits:
+            for v in link.args:
+                if isinstance(v, Variable):
+                    variables_used[v] = True
+
+        for v in variables_used:
+            if v not in variables_created:
+                pending.append((block, v))
+
+    while pending:
+        block, v = pending.pop()
+        v_rep = variable_families.find_rep(v)
+        variables_created = variables_created_in(block)
+        if v in variables_created:
+            continue     # already ok
+        for w in variables_created:
+            w_rep = variable_families.find_rep(w)
+            if v_rep is w_rep:
+                # 'w' is in the same family as 'v', so we can simply
+                # reuse its value for 'v'
+                block.renamevariables({v: w})
+                break
+        else:
+            # didn't find it.  Add it to all incoming links.
+            try:
+                links = entrymap[block]
+            except KeyError:
+                raise Exception("SSA_to_SSI failed: no way to give a value to"
+                                " %r in %r" % (v, block))
+            w = copyvar(annotator, v)
+            variable_families.union(v, w)
+            block.renamevariables({v: w})
+            block.inputargs.append(w)
+            for link in links:
+                link.args.append(v)
+                pending.append((link.prevblock, v))

Modified: pypy/branch/timeshift-refactoring/pypy/translator/backendopt/test/test_ssa.py
==============================================================================
--- pypy/branch/timeshift-refactoring/pypy/translator/backendopt/test/test_ssa.py	(original)
+++ pypy/branch/timeshift-refactoring/pypy/translator/backendopt/test/test_ssa.py	Tue Sep 19 16:57:37 2006
@@ -1,6 +1,7 @@
 from pypy.translator.backendopt.ssa import *
 from pypy.translator.translator import TranslationContext
-from pypy.objspace.flow.model import flatten, Block
+from pypy.objspace.flow.model import flatten, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import SpaceOperation
 
 
 def test_data_flow_families():
@@ -49,3 +50,63 @@
             allvars += [v.name for v in block.getvariables()]
     # see comments above for where the 8 remaining variables are expected to be
     assert len(dict.fromkeys(allvars)) == 8
+
+
+def test_SSA_to_SSI():
+    c = Variable('c')
+    x = Variable('x')
+    y = Variable('y')
+    b1 = Block([c])
+    b2 = Block([x])
+    b3 = Block([])
+
+    b2.operations.append(SpaceOperation('add', [x, c], y))
+    b2.exitswitch = y
+
+    b1.closeblock(Link([Constant(0)], b2))
+    b2.closeblock(Link([y], b2), Link([], b3))
+    b3.closeblock(Link([y, c], None))
+
+    SSA_to_SSI({b1: True,     # reachable from outside
+                b2: False,
+                b3: False})
+
+    assert len(b1.inputargs) == 1
+    assert len(b2.inputargs) == 2
+    assert len(b3.inputargs) == 2
+
+    assert b2.inputargs == b2.operations[0].args
+    assert len(b1.exits[0].args) == 2
+    assert b1.exits[0].args[1] is c
+    assert len(b2.exits[0].args) == 2
+    assert b2.exits[0].args == [y, b2.inputargs[1]]
+    assert len(b2.exits[1].args) == 2
+    assert len(b3.exits[0].args) == 2
+
+    index = b3.inputargs.index(b3.exits[0].args[0])
+    assert b2.exits[1].args[index] is b2.operations[0].result
+
+    index = b3.inputargs.index(b3.exits[0].args[1])
+    assert b2.exits[1].args[index] is b2.inputargs[1]
+
+
+def test_SSA_to_SSI_2():
+    x = Variable('x')
+    y = Variable('y')
+    z = Variable('z')
+    b1 = Block([x])
+    b2 = Block([y])
+    b3 = Block([])
+
+    b3.operations.append(SpaceOperation('hello', [y], z))
+    b1.closeblock(Link([x], b2), Link([], b3))
+
+    SSA_to_SSI({b1: True,     # reachable from outside
+                b2: False,
+                b3: False})
+
+    assert b1.inputargs == [x]
+    assert b2.inputargs == [y]
+    assert b3.inputargs == [b3.operations[0].args[0]]
+    assert b1.exits[0].args == [x]
+    assert b1.exits[1].args == [x]



More information about the Pypy-commit mailing list