]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7042) Added a new compiler optimization (eta-reduce) 34/334/1
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Mon, 20 Feb 2017 09:17:31 +0000 (11:17 +0200)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Mon, 20 Feb 2017 09:17:31 +0000 (11:17 +0200)
Adds new optimization to SCL compiler that transforms the following code
    \someParameters = f someOtherParameters someParameters'
to
    f someOtherParameters
with the following restrictions:
* someParameters and someParameters' are lists of equal variables
  or the type is ()
* someOtherParameters does not refer to variables in someParameters
  or the lambda expression itself or something depending on it
  recursively

[PRIVATE-13082]

Change-Id: I0e666771c72128ab73b0e46af727236ba4811080

bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSAFunction.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/exits/Switch.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClosureRecursion.scl [new file with mode: 0644]
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SwitchSimplification.scl [new file with mode: 0644]

index 68dd82f15f4bb1c76d5b68c07f58cfc501e3f66c..ab643f9a15b1669be060ae165c07a403cb3888c3 100644 (file)
@@ -5,6 +5,7 @@ import java.util.Arrays;
 
 import org.cojen.classfile.TypeDesc;
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.NoRepConstant;
 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
 import org.simantics.scl.compiler.internal.codegen.continuations.ReturnCont;
@@ -173,12 +174,88 @@ public final class SSAFunction extends SSAClosure {
     public void simplify(SSASimplificationContext context) {
         for(SSABlock block = firstBlock; block != null; block = block.next)
             block.simplify(context);
-        if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement &&
-                firstBlock.firstStatement instanceof LetFunctions) {
-            simplifySingleLambda(context);            
+        if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement) {
+            if(firstBlock.firstStatement instanceof LetApply)
+                simplifySingleApply(context);
+            else if(firstBlock.firstStatement instanceof LetFunctions)
+                simplifySingleLambda(context);
         }
     }
     
+    
+    /**
+     * Simplifies the following kind of function definition
+     *     \x -> f x
+     * to
+     *     f
+     */
+    private void simplifySingleApply(SSASimplificationContext context) {
+        if(!(parent instanceof LetFunctions) || parent.getFirstClosure().next != null)
+            return;
+        LetApply apply = (LetApply)firstBlock.firstStatement;
+        if(!(firstBlock.exit instanceof Jump))
+            return;
+        Jump exit = (Jump)firstBlock.exit;
+        if(exit.getTarget().getBinding() != returnCont)
+            return;
+        if(exit.getParameter(0).getBinding() != apply.getTarget())
+            return;
+        BoundVar[] functionParameters = getParameters();
+        ValRef[] applyParameters = apply.getParameters();
+        if(functionParameters.length > applyParameters.length)
+            return;
+        int extraApplyParameters = applyParameters.length - functionParameters.length;
+        for(int i=0;i<functionParameters.length;++i)
+            if(!representSameValues(functionParameters[i], applyParameters[extraApplyParameters+i]))
+                return;
+        for(int i=0;i<extraApplyParameters;++i) {
+            Val b = applyParameters[i].getBinding();
+            if(b instanceof BoundVar) {
+                BoundVar bv = (BoundVar)b;
+                if(bv == target || bv.getParent() == firstBlock)
+                    return;
+            }
+        }
+        if(!(target instanceof BoundVar))
+            return;
+        
+        // Transform
+        
+        LetFunctions binder = (LetFunctions)parent;
+        SSAFunction parentFunction = binder.getParentFunction();
+        if(extraApplyParameters > 0) {
+            //System.out.println("-------------------------------------------------------------");
+            //System.out.println(parentFunction);
+            //System.out.println("-------------------------------------------------------------");
+            apply.setTarget((BoundVar)target);
+            apply.setParameters(Arrays.copyOf(applyParameters, extraApplyParameters));
+            apply.insertBefore(binder);
+            binder.detach();
+            //System.out.println(parentFunction);
+            //System.out.println("-------------------------------------------------------------");
+        }
+        else {
+            binder.detach();
+            ((BoundVar)target).replaceBy(apply.getFunction());
+        }
+        context.markModified("SSAFunction.eta-reduce");
+    }
+    
+    private boolean representSameValues(BoundVar boundVar, ValRef valRef) {
+        Val val = valRef.getBinding(); 
+        if(val == boundVar && valRef.getTypeParameters().length == 0)
+            return true;
+        if(val instanceof NoRepConstant && Types.equals(valRef.getType(), boundVar.getType()))
+            return true;
+        return false;
+    }
+
+    /**
+     * Simplifies the following kind of function definition
+     *     \x -> \y -> e
+     * to
+     *     \x y -> e
+     */
     private void simplifySingleLambda(SSASimplificationContext context) {
         LetFunctions letF = (LetFunctions)firstBlock.firstStatement;
         if(!(letF.getFirstClosure() instanceof SSAFunction))
@@ -202,7 +279,7 @@ public final class SSAFunction extends SSAClosure {
         lastBlock = f.lastBlock;
         
         firstBlock.firstStatement = firstBlock.lastStatement = null;
-        setReturnCont(f.getReturnCont());        
+        setReturnCont(f.getReturnCont());
         effect = f.effect;
         BoundVar[] newParameters = BoundVar.copy(f.firstBlock.parameters);
         firstBlock.setParameters(BoundVar.concat(getParameters(), newParameters));
index 0bcb3dd596e3bc03cbc91779d40232ce3d787c02..27f853e0283b3d714757f4d3369cab4379cf470d 100644 (file)
@@ -6,6 +6,7 @@ import org.objectweb.asm.Label;
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.constants.BooleanConstant;
 import org.simantics.scl.compiler.constants.IntegerConstant;
+import org.simantics.scl.compiler.constants.NoRepConstant;
 import org.simantics.scl.compiler.internal.codegen.continuations.BranchRef;
 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
@@ -223,11 +224,15 @@ public class Switch extends SSAExit implements ValRefBinder {
             context.markModified("switch-to-if");
             newExit.simplify(context);
         }
-        else if(branches.length == 1 && branches[0].constructor == null) {
+        else if(branches.length == 1 && isConstructorParameterless(branches[0])) {
             scrutinee.remove();
             getParent().setExit(new Jump(branches[0].cont));
         }
     }
+    
+    private static boolean isConstructorParameterless(BranchRef branch) {
+        return branch.constructor == null || branch.constructor instanceof NoRepConstant;
+    }
 
     @Override
     public void collectFreeVariables(SSAFunction function,
index 4670b048d62f7b19cdfd9cd1abb2e780de486015..82193b4813df7c3f060cdf460f85ed31c67384b7 100644 (file)
@@ -1,7 +1,5 @@
 package org.simantics.scl.compiler.tests;
 
-import org.junit.Test;
-
 public class ActiveTests extends TestBase {
     
     public ActiveTests() { super("scl"); }
@@ -18,7 +16,6 @@ public class ActiveTests extends TestBase {
     @Test public void TypeClassBug2() { test(); }
   */  
     
-    //@Test public void CityoptSetup() { test(); }
+    //@Test public void Bug6989() { test(); }
     
-    @Test public void Bug6989() { test(); }
 }
index 38506c6f4997070d86d72ca1d3f2222cd707445c..7843bac52d535de9cede7d54950dec3954781992 100644 (file)
@@ -26,6 +26,7 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void CHR2() { test(); }
     @Test public void CHR3() { test(); }
     @Test public void CHR4() { test(); }
+    @Test public void ClosureRecursion() { test(); }
     @Test public void Collaz() { test(); }
     @Test public void Compose() { test(); }
     @Test public void Composition() { test(); }
@@ -224,6 +225,7 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void StringInterpolation3() { test(); }
     @Test public void StringMatching1() { test(); }
     @Test public void SumOfInverses2() { test(); }
+    @Test public void SwitchSimplification() { test(); }
     @Test public void TooManyParametersToSin() { test(); }
     @Test public void Transformation1() { test(); }
     @Test public void Transformation2() { test(); }
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClosureRecursion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClosureRecursion.scl
new file mode 100644 (file)
index 0000000..4b31b1d
--- /dev/null
@@ -0,0 +1,21 @@
+import "Prelude"
+
+countDown :: Ref Integer -> <Proc> Boolean
+countDown r = if currentValue <= 0
+              then False
+              else do 
+                  r := currentValue - 1
+                  True
+  where
+    currentValue = getRef r 
+
+strangeLoop :: (<Proc> Boolean) -> <Proc> ()
+strangeLoop cond = if cond
+                   then strangeLoop cond
+                   else ()
+
+main = do
+    r = ref 100000 :: Ref Integer
+    strangeLoop (countDown r)
+--
+()
\ No newline at end of file
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SwitchSimplification.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SwitchSimplification.scl
new file mode 100644 (file)
index 0000000..8ea1d01
--- /dev/null
@@ -0,0 +1,5 @@
+foo () = "asd"
+
+main = foo ()
+--
+asd
\ No newline at end of file