1 package org.simantics.scl.compiler.internal.codegen.analysis;
3 import org.simantics.scl.compiler.common.names.Name;
4 import org.simantics.scl.compiler.common.names.Names;
5 import org.simantics.scl.compiler.constants.SCLConstant;
6 import org.simantics.scl.compiler.internal.codegen.references.Val;
7 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
8 import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
9 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
10 import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
11 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
13 import gnu.trove.set.hash.THashSet;
15 public class LoopAnalysis {
18 * Checks if it is possible to return to the loop after exiting
19 * before exiting the function where the block belongs to.
21 private static boolean isLoopingBlock(SSABlock block) {
22 THashSet<SSABlock> handled = new THashSet<SSABlock>();
23 for(SSABlock succBlock : block.getExit().getSuccessors())
24 if(isLoopingBlock(block, handled, succBlock))
30 * Checks if it is possible to execute block more than once without visiting
31 * the breaker block. It is assumed that breaker is a dominator of the block.
33 public static boolean isLoopingBlockWithBreaker(SSABlock block, SSABlock breaker) {
34 SSAFunction function = block.getParent();
36 if(function == block.getParent()) {
37 THashSet<SSABlock> handled = new THashSet<SSABlock>();
39 for(SSABlock succBlock : block.getExit().getSuccessors())
40 if(isLoopingBlock(block, handled, succBlock))
45 if(isLoopingBlock(block))
47 Val functionTarget = function.getTarget();
48 if(functionTarget.hasMoreThanOneOccurences())
50 ValRef occ = functionTarget.getOccurrence();
53 ValRefBinder occParent = occ.getParent();
54 if(!(occParent instanceof LetApply))
55 return true; // Not necessarily the right answer, but we don't try to analyse further
56 LetApply apply = (LetApply)occParent;
57 if(!isAppliedAtMostOnce(apply, occ, function))
59 return isLoopingBlockWithBreaker(apply.getParent(), breaker);
63 private static boolean isAppliedAtMostOnce(LetApply apply, ValRef funRef, SSAFunction function) {
64 ValRef applyFunctionRef = apply.getFunction();
65 if(funRef == applyFunctionRef) {
66 return apply.getParameters().length == function.getArity();
68 Val applyFunction = applyFunctionRef.getBinding();
69 if(!(applyFunction instanceof SCLConstant))
70 return false; // Not necessarily the right answer
71 Name name = ((SCLConstant)applyFunction).getName();
72 if(name == Names.Prelude_build)
77 private static boolean isLoopingBlock(SSABlock originalBlock,
78 THashSet<SSABlock> handled, SSABlock block) {
79 if(!handled.add(block))
81 if(block == originalBlock)
83 for(SSABlock succBlock : block.getExit().getSuccessors())
84 if(isLoopingBlock(originalBlock, handled, succBlock))