Author: Remi Meier <remi.me...@gmail.com>
Branch: stmgc-c8
Changeset: r80975:3df49e2a17bd
Date: 2015-11-26 12:44 +0100
http://bitbucket.org/pypy/pypy/changeset/3df49e2a17bd/

Log:    wip: implement generic forward data flow analysis

        First requires some uses to determine if it is generic and
        convenient enough

diff --git a/rpython/translator/backendopt/dataflow.py 
b/rpython/translator/backendopt/dataflow.py
new file mode 100644
--- /dev/null
+++ b/rpython/translator/backendopt/dataflow.py
@@ -0,0 +1,88 @@
+from rpython.flowspace.model import mkentrymap
+
+
+
+class AbstractDataFlowAnalysis(object):
+
+    def transfer_function(self, block, in_state):
+        """Returns a new out_state after flowing the 'in_state'
+        through 'block'"""
+        raise NotImplementedError("abstract base class")
+
+    def entry_state(self, block):
+        """Returns the initial state for the 'block' with which
+        the analysis starts.
+            Forward: start block
+            Backwards: return block"""
+        raise NotImplementedError("abstract base class")
+
+    def initialize_block(self, block):
+        """Return the (default) in_state, out_state for 'block'
+        used to initialize all blocks before starting the analysis"""
+        raise NotImplementedError("abstract base class")
+
+    def join_operation(self, preds_outs, inputargs, pred_out_args):
+        """Joins all preds_outs to generate a new in_state for the
+        current block.
+        'inputargs' is the list of input arguments to the block;
+        'pred_out_args' is a list of lists of arguments given to
+            the link by a certain predecessor.
+        """
+        raise NotImplementedError("abstract base class")
+
+    def calculate(self, graph, entrymap=None):
+        """Run the analysis on 'graph' and return the in and
+        out states as two {block:state} dicts"""
+        raise NotImplementedError("abstract base class")
+
+
+
+
+
+class AbstractForwardDataFlowAnalysis(AbstractDataFlowAnalysis):
+
+    def _update_successor_blocks(self, block, out_state, entrymap,
+                                 in_states, out_states):
+        if out_states[block] == out_state:
+            return set()
+        out_states[block] = out_state
+        #
+        # update all successors
+        to_do = set()
+        for link in block.exits:
+            succ = link.target
+            # collect all out_states of predecessors:
+            preds_outs = []
+            inputargs = succ.inputargs
+            preds_out_args = [[] for _ in inputargs]
+            for link in entrymap[succ]:
+                preds_outs.append(out_states[link.prevblock])
+                for i in range(len(inputargs)):
+                    preds_out_args[i].append(link.args[i])
+            block_in = self.join_operation(preds_outs, inputargs, 
preds_out_args)
+            if block_in != in_states[succ]:
+                # in_state changed
+                to_do.add(succ)
+                in_states[succ] = block_in
+        return to_do
+
+
+    def calculate(self, graph, entrymap=None):
+        if entrymap is None:
+            entrymap = mkentrymap(graph)
+        in_states = {}
+        out_states = {}
+        #
+        for block in graph.iterblocks():
+            in_states[block], out_states[block] = self.initialize_block(block)
+        in_states[graph.startblock] = self.entry_state(graph.startblock)
+        #
+        # iterate:
+        pending = {graph.startblock,}
+        while pending:
+            block = pending.pop()
+            block_out = self.transfer_function(block, in_states[block])
+            pending |= self._update_successor_blocks(
+                block, block_out, entrymap, in_states, out_states)
+        #
+        return in_states, out_states
diff --git a/rpython/translator/backendopt/test/test_dataflow.py 
b/rpython/translator/backendopt/test/test_dataflow.py
new file mode 100644
--- /dev/null
+++ b/rpython/translator/backendopt/test/test_dataflow.py
@@ -0,0 +1,65 @@
+import random
+from rpython.tool.algo.unionfind import UnionFind
+from rpython.translator.backendopt.dataflow import 
AbstractForwardDataFlowAnalysis
+
+
+
+from rpython.translator.translator import TranslationContext, graphof
+
+
+class SimpleForwardAnalysis(AbstractForwardDataFlowAnalysis):
+    def __init__(self):
+        self.seen = set()
+
+    def transfer_function(self, block, in_state):
+        self.seen.add(block)
+        return in_state
+
+    def entry_state(self, block):
+        return True
+
+    def initialize_block(self, block):
+        return False, False
+
+    def join_operation(self, preds_outs, inputargs, pred_out_args):
+        return any(preds_outs)
+
+
+def test_simple_forward_flow():
+    def f(x):
+        if x < 0:
+            if x == -1:
+                return x+1
+            else:
+                return x+2
+        else:
+            if x == 1:
+                return x-1
+            else:
+                return x-2
+    t = TranslationContext()
+    g = t.buildflowgraph(f)
+    sfa = SimpleForwardAnalysis()
+    ins, outs = sfa.calculate(g)
+    assert len(sfa.seen) == 8
+    assert ins[g.startblock] == sfa.entry_state(None)
+    assert outs[g.returnblock] == sfa.entry_state(None)
+
+def test_loopy_forward_flow():
+    def f(x):
+        if x < 0:
+            while x:
+                pass
+            return x
+        else:
+            while x:
+                if x-1:
+                    return x
+    t = TranslationContext()
+    g = t.buildflowgraph(f)
+    sfa = SimpleForwardAnalysis()
+    ins, outs = sfa.calculate(g)
+    g.show()
+    assert len(sfa.seen) == 5
+    assert ins[g.startblock] == sfa.entry_state(None)
+    assert outs[g.returnblock] == sfa.entry_state(None)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to