]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7088) Improvements to tail call optimization
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 15 Mar 2017 08:46:21 +0000 (10:46 +0200)
committerjsimomaa <jani.simomaa@gmail.com>
Fri, 28 Apr 2017 13:19:43 +0000 (16:19 +0300)
Change-Id: I7e6b914c239b1aa81a06ad9da2cdbf046ac5e0e2

bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSABlock.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/SSAUtils.java [new file with mode: 0644]

index c9f33ec50c7727e8a9c789858de926bfce31a282..aaab03e1aae8c3e49686ec7d1960c4dc9dbf1b44 100644 (file)
@@ -4,6 +4,7 @@ import java.util.ArrayList;
 
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.constants.NoRepConstant;
 import org.simantics.scl.compiler.constants.SCLConstant;
 import org.simantics.scl.compiler.internal.codegen.continuations.BranchRef;
 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
@@ -21,6 +22,7 @@ import org.simantics.scl.compiler.internal.codegen.utils.Printable;
 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
 import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSAUtils;
 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
 import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
@@ -281,27 +283,42 @@ public final class SSABlock extends Cont implements Printable, BoundVarBinder {
             context.markModified("improve-parameters");
     }
 
+    private static Constant getOnlyPossibleValue(Type type) {
+        type = Types.canonical(type);
+        if(type == Types.UNIT)
+            return NoRepConstant.UNIT;
+        else if(type == Types.PUNIT)
+            return NoRepConstant.PUNIT;
+        return null; 
+    }
+    
     private boolean tryToImproveParameter(int position) {
         BoundVar parameter = parameters[position];
-        Val constant = null;
-        ValRef constantRef = null;
-        for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext()) {
-            Jump jump = (Jump)ref.getParent();
-            ValRef valRef = jump.getParameters()[position];
-            Val val = valRef.getBinding();
-            if(val == parameter)
-                continue;
-            if(constant == null) {
-                constant = val;
-                constantRef = valRef;
-                continue;
+        Constant onlyPossibleValue = getOnlyPossibleValue(parameter.getType());
+        if(onlyPossibleValue == null) {
+            Val constant = null;
+            ValRef constantRef = null;
+            for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext()) {
+                Jump jump = (Jump)ref.getParent();
+                ValRef valRef = jump.getParameters()[position];
+                Val val = valRef.getBinding();
+                if(val == parameter)
+                    continue;
+                if(constant == null) {
+                    constant = val;
+                    constantRef = valRef;
+                    continue;
+                }
+                if(val != constant)
+                    return false;
             }
-            if(val != constant)
-                return false;
+            if(constant == null)
+                return false; // This is a strange case, because we cannot get the parameter anywhere
+            parameter.replaceBy(constantRef);
+        }
+        else {
+            parameter.replaceBy(onlyPossibleValue);
         }
-        if(constant == null)
-            return false; // This is a strange case, because we cannot get the parameter anywhere
-        parameter.replaceBy(constantRef);
         
         for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext()) {
             Jump jump = (Jump)ref.getParent();
@@ -331,32 +348,72 @@ public final class SSABlock extends Cont implements Printable, BoundVarBinder {
         return result;
     }
     
+    /*
+     * This method assumes that the exit of the block is Jump.
+     */
     private boolean optimizeTailSelfCall() {
-        Jump jump = (Jump)exit;
-        if(jump.getTarget().getBinding() != parent.returnCont)
-            return false;
-        if(jump.getParameters().length != 1)
-            return false;
+        // The last statement of the block is LetApply that calls the parent function with right number of parameters 
         if(lastStatement == null || !(lastStatement instanceof LetApply))
             return false;
         LetApply apply = (LetApply)lastStatement;
-        SSABlock initialBlock = parent.firstBlock;
-        if(initialBlock.parameters.length != apply.getParameters().length)
-            return false;
         Val function = apply.getFunction().getBinding();
         if(function != parent.target)
             return false;
+        SSABlock initialBlock = parent.firstBlock;
+        if(initialBlock.parameters.length != apply.getParameters().length)
+            return false;
+
+        // The jump is a return (with one parameter)
+        // The parameter of the jump is the target of LetApply
+        Jump jump = (Jump)exit;
+        Cont targetCont = jump.getTarget().getBinding();
+        if(targetCont != parent.returnCont) {
+            SSABlock targetBlock = (SSABlock)targetCont;
+            if(targetBlock.firstStatement != null)
+                return false;
+            if(!(targetBlock.exit instanceof Jump))
+                return false;
+            Jump targetJump = (Jump)targetBlock.exit;
+            if(targetJump.getTarget().getBinding() != parent.returnCont)
+                return false;
+            if(targetJump.getParameters().length != 1)
+                return false;
+            
+            BoundVar applyTarget = apply.getTarget();
+            ValRef targetJumpParameter = targetJump.getParameter(0);
+            isSameParam: if(!SSAUtils.representSameValue(applyTarget, targetJumpParameter)) {
+                BoundVar[] targetBlockParameters = targetBlock.getParameters();
+                for(int i=0;i<targetBlockParameters.length;++i) {
+                    if(targetJumpParameter.getBinding() == targetBlockParameters[i]
+                            && jump.getParameter(i).getBinding() == applyTarget)
+                        break isSameParam;
+                }
+                return false;
+            }
+        }
+        else {
+            if(jump.getParameters().length != 1)
+                return false;
+            if(!SSAUtils.representSameValue(apply.getTarget(), jump.getParameter(0)))
+                return false;
+        }
         
         // Do modifications
         apply.detach();
         apply.getFunction().remove();
         jump.getTarget().remove();
         jump.setTarget(initialBlock.createOccurrence());
+        for(ValRef parameter : jump.getParameters())
+            parameter.remove();
         jump.setParameters(apply.getParameters());
         
         return true;
     }
 
+    /**
+     * Assumes that this block has no statements, the block is not the first block
+     * and the exit of the block is Jump.
+     */
     private boolean etaBlock(SSASimplificationContext context) {
         Jump jump = (Jump)exit;
         if(parameters.length != jump.getParameters().length)
@@ -436,7 +493,7 @@ public final class SSABlock extends Cont implements Printable, BoundVarBinder {
         block.detach();
         
         jump.destroy();
-        setExit(block.exit);       
+        setExit(block.exit);
         
         /*System.out.println(">> AFTER INLINE >>");
         System.out.println(getParent());
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/SSAUtils.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/SSAUtils.java
new file mode 100644 (file)
index 0000000..7de1ab4
--- /dev/null
@@ -0,0 +1,31 @@
+package org.simantics.scl.compiler.internal.codegen.utils;
+
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+public class SSAUtils {
+
+    public static boolean representSameValue(Val a, ValRef b) {
+        if(b.getTypeParameters().length > 0)
+            return false;
+        return representSameValue(a, b.getBinding());
+    }
+    
+    public static boolean representSameValue(Val a, Val b) {
+        if(a == b)
+            return true;
+        Type aT = a.getType();
+        Type bT = b.getType();
+        if(!Types.equals(aT, bT))
+            return false;
+        return isSingletonType(aT);
+    }
+
+    public static boolean isSingletonType(Type type) {
+        type = Types.canonical(type);
+        return type == Types.UNIT || type == Types.PUNIT;
+    }
+    
+}