-package org.simantics.scl.compiler.internal.codegen.analysis;\r
-\r
-import org.simantics.scl.compiler.common.names.Name;\r
-import org.simantics.scl.compiler.common.names.Names;\r
-import org.simantics.scl.compiler.constants.SCLConstant;\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.binders.ValRefBinder;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;\r
-\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-public class LoopAnalysis {\r
-\r
- /**\r
- * Checks if it is possible to return to the loop after exiting \r
- * before exiting the function where the block belongs to.\r
- */\r
- private static boolean isLoopingBlock(SSABlock block) {\r
- THashSet<SSABlock> handled = new THashSet<SSABlock>();\r
- for(SSABlock succBlock : block.getExit().getSuccessors())\r
- if(isLoopingBlock(block, handled, succBlock))\r
- return true;\r
- return false;\r
- }\r
-\r
- /**\r
- * Checks if it is possible to execute block more than once without visiting\r
- * the breaker block. It is assumed that breaker is a dominator of the block.\r
- */\r
- public static boolean isLoopingBlockWithBreaker(SSABlock block, SSABlock breaker) {\r
- SSAFunction function = block.getParent();\r
- \r
- if(function == block.getParent()) { \r
- THashSet<SSABlock> handled = new THashSet<SSABlock>();\r
- handled.add(breaker);\r
- for(SSABlock succBlock : block.getExit().getSuccessors())\r
- if(isLoopingBlock(block, handled, succBlock))\r
- return true;\r
- return false;\r
- }\r
- else {\r
- if(isLoopingBlock(block))\r
- return false;\r
- Val functionTarget = function.getTarget();\r
- if(functionTarget.hasMoreThanOneOccurences())\r
- return false;\r
- ValRef occ = functionTarget.getOccurrence();\r
- if(occ == null)\r
- return false;\r
- ValRefBinder occParent = occ.getParent();\r
- if(!(occParent instanceof LetApply))\r
- return true; // Not necessarily the right answer, but we don't try to analyse further\r
- LetApply apply = (LetApply)occParent;\r
- if(!isAppliedAtMostOnce(apply, occ, function))\r
- return true;\r
- return isLoopingBlockWithBreaker(apply.getParent(), breaker);\r
- }\r
- } \r
- \r
- private static boolean isAppliedAtMostOnce(LetApply apply, ValRef funRef, SSAFunction function) {\r
- ValRef applyFunctionRef = apply.getFunction();\r
- if(funRef == applyFunctionRef) { \r
- return apply.getParameters().length == function.getArity();\r
- }\r
- Val applyFunction = applyFunctionRef.getBinding();\r
- if(!(applyFunction instanceof SCLConstant))\r
- return false; // Not necessarily the right answer\r
- Name name = ((SCLConstant)applyFunction).getName();\r
- if(name == Names.Prelude_build)\r
- return true;\r
- return false;\r
- }\r
-\r
- private static boolean isLoopingBlock(SSABlock originalBlock,\r
- THashSet<SSABlock> handled, SSABlock block) {\r
- if(!handled.add(block))\r
- return false;\r
- if(block == originalBlock)\r
- return true;\r
- for(SSABlock succBlock : block.getExit().getSuccessors())\r
- if(isLoopingBlock(originalBlock, handled, succBlock))\r
- return true;\r
- return false;\r
- }\r
- \r
-}\r
+package org.simantics.scl.compiler.internal.codegen.analysis;
+
+import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.common.names.Names;
+import org.simantics.scl.compiler.constants.SCLConstant;
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
+import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
+
+import gnu.trove.set.hash.THashSet;
+
+public class LoopAnalysis {
+
+ /**
+ * Checks if it is possible to return to the loop after exiting
+ * before exiting the function where the block belongs to.
+ */
+ private static boolean isLoopingBlock(SSABlock block) {
+ THashSet<SSABlock> handled = new THashSet<SSABlock>();
+ for(SSABlock succBlock : block.getExit().getSuccessors())
+ if(isLoopingBlock(block, handled, succBlock))
+ return true;
+ return false;
+ }
+
+ /**
+ * Checks if it is possible to execute block more than once without visiting
+ * the breaker block. It is assumed that breaker is a dominator of the block.
+ */
+ public static boolean isLoopingBlockWithBreaker(SSABlock block, SSABlock breaker) {
+ SSAFunction function = block.getParent();
+
+ if(function == block.getParent()) {
+ THashSet<SSABlock> handled = new THashSet<SSABlock>();
+ handled.add(breaker);
+ for(SSABlock succBlock : block.getExit().getSuccessors())
+ if(isLoopingBlock(block, handled, succBlock))
+ return true;
+ return false;
+ }
+ else {
+ if(isLoopingBlock(block))
+ return false;
+ Val functionTarget = function.getTarget();
+ if(functionTarget.hasMoreThanOneOccurences())
+ return false;
+ ValRef occ = functionTarget.getOccurrence();
+ if(occ == null)
+ return false;
+ ValRefBinder occParent = occ.getParent();
+ if(!(occParent instanceof LetApply))
+ return true; // Not necessarily the right answer, but we don't try to analyse further
+ LetApply apply = (LetApply)occParent;
+ if(!isAppliedAtMostOnce(apply, occ, function))
+ return true;
+ return isLoopingBlockWithBreaker(apply.getParent(), breaker);
+ }
+ }
+
+ private static boolean isAppliedAtMostOnce(LetApply apply, ValRef funRef, SSAFunction function) {
+ ValRef applyFunctionRef = apply.getFunction();
+ if(funRef == applyFunctionRef) {
+ return apply.getParameters().length == function.getArity();
+ }
+ Val applyFunction = applyFunctionRef.getBinding();
+ if(!(applyFunction instanceof SCLConstant))
+ return false; // Not necessarily the right answer
+ Name name = ((SCLConstant)applyFunction).getName();
+ if(name == Names.Prelude_build)
+ return true;
+ return false;
+ }
+
+ private static boolean isLoopingBlock(SSABlock originalBlock,
+ THashSet<SSABlock> handled, SSABlock block) {
+ if(!handled.add(block))
+ return false;
+ if(block == originalBlock)
+ return true;
+ for(SSABlock succBlock : block.getExit().getSuccessors())
+ if(isLoopingBlock(originalBlock, handled, succBlock))
+ return true;
+ return false;
+ }
+
+}