]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/analysis/StatementBrowser.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / analysis / StatementBrowser.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/analysis/StatementBrowser.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/analysis/StatementBrowser.java
new file mode 100644 (file)
index 0000000..5760890
--- /dev/null
@@ -0,0 +1,203 @@
+package org.simantics.scl.compiler.internal.codegen.analysis;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
+import org.simantics.scl.compiler.common.names.Name;\r
+import org.simantics.scl.compiler.constants.SCLConstant;\r
+import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;\r
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;\r
+import org.simantics.scl.compiler.internal.codegen.references.Val;\r
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;\r
+\r
+public abstract class StatementBrowser {\r
+\r
+    THashSet<SSABlock> visited;\r
+    THashMap<SSABlock,SSAStatement> loopPos;\r
+    SSAStatement fromStatement;\r
+    SSABlock fromBlock;\r
+    \r
+    boolean stopBrowse = false;\r
+    \r
+    protected void stopBrowse() {\r
+        stopBrowse = true;\r
+    }\r
+    \r
+    public boolean isStopped() {\r
+        return stopBrowse;\r
+    }\r
+    \r
+    /**\r
+     * Browses all statements that are potentially executed\r
+     * between from and to.\r
+     */\r
+    public void browseBetween(SSAStatement from, SSAStatement to) {\r
+        SSABlock toBlock = to.getParent();\r
+        if(from.getParent() == toBlock) {\r
+            for(SSAStatement cur = from.getNext(); cur != to; cur = cur.getNext()) {\r
+                if(cur == null)\r
+                    dominationError();\r
+                visitStatement(cur);\r
+                if(stopBrowse)\r
+                    return;\r
+            }\r
+        }\r
+        else {\r
+            for(SSAStatement cur = to.getPrev(); cur != null; cur = cur.getPrev()) {\r
+                visitStatement(cur);\r
+                if(stopBrowse)\r
+                    return;\r
+            }\r
+\r
+            visited = new THashSet<SSABlock>();            \r
+            fromStatement = from;\r
+            fromBlock = from.getParent();\r
+            \r
+            loopPos = new THashMap<SSABlock,SSAStatement>();\r
+            loopPos.put(toBlock, to);\r
+\r
+            browsePredecessors(toBlock);            \r
+        }\r
+    }\r
+    \r
+    private void browseBetweenRec(SSAStatement to) {\r
+        SSABlock toBlock = to.getParent();\r
+        if(fromBlock == toBlock) {\r
+            for(SSAStatement cur = fromStatement.getNext(); cur != to; cur = cur.getNext()) {\r
+                if(cur == null)\r
+                    dominationError();\r
+                visitStatement(cur);\r
+                if(stopBrowse)\r
+                    return;\r
+            }\r
+        }\r
+        else {\r
+            for(SSAStatement cur = to.getPrev(); cur != null; cur = cur.getPrev()) {\r
+                visitStatement(cur);\r
+                if(stopBrowse)\r
+                    return;\r
+            }\r
+            loopPos.put(toBlock, to);\r
+            browsePredecessors(to.getParent());            \r
+        }\r
+    }\r
+    \r
+    private void browsePredecessors(SSABlock block) {\r
+        for(ContRef contRef = block.getOccurrence(); contRef != null; contRef = contRef.getNext()) {\r
+            browse(contRef.getParent().getParent());\r
+            if(stopBrowse)\r
+                return;\r
+        }\r
+    }    \r
+    \r
+    private void browse(SSABlock block) {\r
+        if(!visited.add(block))\r
+            return;\r
+        if(block == fromBlock) {\r
+            for(SSAStatement cur = fromStatement.getNext(); cur != null; cur = cur.getNext()) {\r
+                visitStatement(cur);\r
+                if(stopBrowse)\r
+                    return;\r
+            }\r
+            return;\r
+        }\r
+        if(loopPos.contains(block)) {\r
+            handleLoop(block, loopPos.get(block));\r
+            return;\r
+        }\r
+        for(SSAStatement cur = block.getFirstStatement(); cur != null; cur = cur.getNext()) {\r
+            visitStatement(cur);\r
+            if(stopBrowse)\r
+                return;\r
+        }\r
+        browsePredecessors(block);\r
+        if(stopBrowse)\r
+            return;\r
+        if(block.getPrev() == null) {\r
+            SSAFunction function = block.getParent();\r
+            if(function == fromBlock.getParent())\r
+                dominationError();\r
+            Val functionTarget = function.getTarget();\r
+            if(functionTarget instanceof BoundVar)\r
+                browseFunction((BoundVar)functionTarget, function.getArity());\r
+            else\r
+                dominationError();\r
+        }\r
+    }\r
+    \r
+    private static void dominationError() {\r
+        throw new InternalCompilerError("Statement 'from' does not dominate the statement 'to'.");\r
+    }\r
+\r
+    protected void browseFunction(BoundVar function, int arity) {\r
+        for(ValRef cur = function.getOccurrence(); cur != null; cur = cur.getNext()) {\r
+            ValRefBinder binder = cur.getParent();\r
+            if(binder instanceof LetApply)\r
+                browseApply((LetApply)binder, cur, arity);\r
+            else\r
+                unanalyzedBrowse();\r
+            if(stopBrowse)\r
+                return;\r
+        }\r
+    }\r
+    \r
+    private static final Name BUILD = Name.create("Prelude", "build");\r
+    \r
+    private static boolean callsOnlyOnce(Name name, int arity) {\r
+        if(name == BUILD)\r
+            return arity == 1;\r
+        else\r
+            return false;\r
+    }\r
+    \r
+    protected void browseApply(LetApply apply, ValRef functionRef, int arity) {\r
+        ValRef applyFunctionRef = apply.getFunction(); \r
+        if(applyFunctionRef == functionRef) {\r
+            if(apply.getParameters().length == arity)\r
+                browseBetweenRec(apply);\r
+            else\r
+                unanalyzedBrowse();\r
+        }\r
+        else {\r
+            Val applyFunction = applyFunctionRef.getBinding();\r
+            if(!(applyFunction instanceof SCLConstant)) {\r
+                unanalyzedBrowse();\r
+                return;\r
+            }\r
+            Name name = ((SCLConstant)applyFunction).getName();\r
+            if(callsOnlyOnce(name, arity))\r
+                browseBetweenRec(apply);\r
+            else\r
+                unanalyzedBrowse();\r
+        }\r
+    }\r
+    \r
+    protected void unanalyzedBrowse() {\r
+    }\r
+\r
+    protected void visitStatement(SSAStatement statement) {        \r
+    }\r
+    \r
+    protected void handleLoop(SSABlock block, SSAStatement recursiveStatement) {\r
+        for(SSAStatement cur = recursiveStatement; cur != null; cur = cur.getNext()) {\r
+            visitStatement(cur);\r
+            if(stopBrowse)\r
+                return;\r
+        }\r
+    }\r
+    \r
+    public boolean doesAlwaysReach() {\r
+        for(SSABlock block : visited)\r
+            for(SSABlock successor : block.getExit().getSuccessors())\r
+                if(!visited.contains(successor))\r
+                    return false;\r
+        return true;\r
+    }\r
+    \r
+}\r