]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java
(refs #7250) Merging master, minor CHR bugfixes
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / statements / LetApply.java
index 83b1e0cb67a81afe13249ace83f230097b2ed892..400cb6e4e373f78c480e8fc37c1da3dc203a47f2 100644 (file)
-package org.simantics.scl.compiler.internal.codegen.ssa.statements;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-\r
-import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
-import org.simantics.scl.compiler.constants.Constant;\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.SSAExit;\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.BoundVarBinder;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.exits.Switch;\r
-import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;\r
-import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;\r
-import org.simantics.scl.compiler.top.SCLCompilerConfiguration;\r
-import org.simantics.scl.compiler.types.TVar;\r
-import org.simantics.scl.compiler.types.Type;\r
-import org.simantics.scl.compiler.types.Types;\r
-import org.simantics.scl.compiler.types.exceptions.MatchException;\r
-import org.simantics.scl.compiler.types.util.MultiFunction;\r
-\r
-public class LetApply extends LetStatement implements ValRefBinder {\r
-    private ValRef function;\r
-    private ValRef[] parameters;\r
-    Type effect;\r
-    \r
-    public LetApply(BoundVar target, Type effect, ValRef function, ValRef ... parameters) {\r
-        super(target);\r
-        if(SCLCompilerConfiguration.DEBUG) {\r
-            if(effect == null)\r
-                throw new InternalCompilerError();\r
-            if(function.getBinding() == null)\r
-                throw new InternalCompilerError();\r
-        }\r
-        this.setFunction(function);\r
-        this.setParameters(parameters);\r
-        this.effect = Types.canonical(effect);\r
-    }\r
-\r
-    public void push(MethodBuilder mb) {\r
-        //mb.getCodeBuilder().mapLineNumber(lineNumber);\r
-        Val f = getFunction().getBinding();\r
-        Val[] ps = ValRef.getBindings(getParameters());\r
-        if(f instanceof Constant) {\r
-            Constant cf = (Constant)f;\r
-            Type returnType = cf.apply(mb, getFunction().getTypeParameters(), ps);\r
-            if(Types.isBoxed(returnType))\r
-                mb.unbox(target.getType());\r
-        }\r
-        else {            \r
-            mb.push(f, f.getType());\r
-            mb.pushBoxed(ps);\r
-            mb.genericApply(ps.length);\r
-            mb.unbox(target.getType());\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public void generateCode(MethodBuilder mb) {\r
-        if(!target.generateOnFly) {\r
-            push(mb);\r
-            mb.store(target);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void toString(PrintingContext context) {\r
-        if(determineGenerateOnFly())\r
-            context.addInlineExpression(target, this);\r
-        else\r
-            toStringAux(context);\r
-    }\r
-    \r
-    private void toStringAux(PrintingContext context) {\r
-        context.indentation();\r
-        context.append(target);\r
-        context.append("(" + target.occurrenceCount() + ")");\r
-        context.append(" = ");\r
-        bodyToString(context);\r
-        context.append('\n');\r
-        \r
-    }\r
-    \r
-    public void bodyToString(PrintingContext context) {\r
-        if(context.getErrorMarker() == this)\r
-            context.append("!> ");\r
-        if(hasEffect()) {\r
-            context.append("<");\r
-            context.append(effect);\r
-            context.append("> ");\r
-        }\r
-        context.append(getFunction());\r
-        for(ValRef parameter : getParameters()) {\r
-            context.append(' ');\r
-            context.append(parameter);\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public String toString() {\r
-        PrintingContext context = new PrintingContext();\r
-        toStringAux(context);\r
-        return context.toString();\r
-    }\r
-\r
-    @Override\r
-    public void validate(SSAValidationContext context) {\r
-        context.validate(target);\r
-        if(target.getParent() != this)\r
-            throw new InternalCompilerError();\r
-        context.validate(function);\r
-        if(function.getParent() != this)\r
-            throw new InternalCompilerError();\r
-        for(ValRef parameter : parameters) {\r
-            context.validate(parameter);\r
-            if(parameter.getParent() != this)\r
-                throw new InternalCompilerError();\r
-        }\r
-        //if(parameters.length == 0)\r
-        //    throw new InternalCompilerError();\r
-        \r
-        \r
-        MultiFunction mFun;\r
-        try {\r
-            mFun = Types.matchFunction(getFunction().getType(), getParameters().length);\r
-        } catch (MatchException e) {\r
-            context.setErrorMarker(this);\r
-            throw new InternalCompilerError();\r
-        }\r
-        for(int i=0;i<getParameters().length;++i)\r
-            context.assertSubsumes(this, getParameters()[i].getType(), mFun.parameterTypes[i]);\r
-        context.assertSubsumes(this, target.getType(), mFun.returnType);\r
-        context.assertEqualsEffect(this, effect, mFun.effect);\r
-    }\r
-\r
-    @Override\r
-    public void destroy() {\r
-        getFunction().remove();\r
-        for(ValRef parameter : getParameters())\r
-            parameter.remove();\r
-    }\r
-    \r
-    @Override\r
-    public void simplify(SSASimplificationContext context) {\r
-        if(target.hasNoOccurences() && !hasEffect()) {\r
-            remove();\r
-            context.markModified("LetApply.dead-let-statement");\r
-            return;\r
-        }\r
-        Val functionVal = getFunction().getBinding();\r
-        if(functionVal instanceof BoundVar) {\r
-            BoundVarBinder parent_ = ((BoundVar)functionVal).parent;\r
-            if(parent_ instanceof SSAFunction) {\r
-                SSAFunction function = (SSAFunction)parent_;\r
-                if(functionVal.hasMoreThanOneOccurences())\r
-                    return;\r
-                if(getParameters().length < function.getArity())\r
-                    return;\r
-                if(getParameters().length > function.getArity())\r
-                    split(function.getArity());\r
-                inline(function);\r
-                function.detach();\r
-                context.markModified("LetApply.beta-lambda");\r
-            }\r
-            else if(parent_ instanceof LetApply) {\r
-                LetApply apply = (LetApply)parent_;\r
-                if(apply.hasEffect())\r
-                    return;\r
-                boolean hasJustOneOccurence = !functionVal.hasMoreThanOneOccurences();\r
-                if((hasJustOneOccurence && apply.getParent() == getParent()) ||\r
-                        apply.isPartial()) {\r
-                    if(hasJustOneOccurence) {\r
-                        apply.detach();\r
-                        setFunction(apply.getFunction());\r
-                        setParameters(ValRef.concat(apply.getParameters(), getParameters()));\r
-                    }\r
-                    else {\r
-                        setFunction(apply.getFunction().copy());\r
-                        setParameters(ValRef.concat(ValRef.copy(apply.getParameters()), getParameters()));\r
-                    }\r
-                    context.markModified("LetApply.merge-applications");\r
-                }\r
-            }\r
-            else if(parent_ instanceof SSABlock) {\r
-                SSABlock parent = getParent();\r
-                if(parent_ != parent)\r
-                    return;\r
-                if(parent.getFirstStatement() != this)\r
-                    return;\r
-                if(!parent.hasMoreThanOneOccurences())\r
-                    return; // We stop here, because situation can be handled by better transformations\r
-                if(functionVal.hasMoreThanOneOccurences())\r
-                    return;\r
-                // We have now the following situation:\r
-                //    [c] ... f ... =\r
-                //        x = f ... \r
-                // * this application is the only reference to f\r
-                // * there are multiple references to [c]\r
-                for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext())\r
-                    if(!(ref.getParent() instanceof Jump))\r
-                        return;\r
-                \r
-                // Finds the position of the functionVal in the parameter list of \r
-                // the parent block.\r
-                int position;\r
-                for(position=0;position<parent.getParameters().length;++position)\r
-                    if(parent.getParameters()[position] == functionVal)\r
-                        break;\r
-                if(position == parent.getParameters().length)\r
-                    throw new InternalCompilerError();\r
-                \r
-                // Do tranformation\r
-                for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext()) {\r
-                    Jump jump = (Jump)ref.getParent();\r
-                    SSABlock block = jump.getParent();\r
-                    \r
-                    BoundVar newTarget = new BoundVar(target.getType());\r
-                    block.addStatement(new LetApply(newTarget, effect, jump.getParameter(position), ValRef.copy(parameters)));\r
-                    jump.setParameter(position, newTarget.createOccurrence());\r
-                }\r
-                \r
-                parent.setParameter(position, target);\r
-                remove();\r
-                context.markModified("LetApply.hoist-apply");\r
-            }\r
-        }\r
-        else if(functionVal instanceof Constant) {\r
-            ((Constant)functionVal).inline(context, this);\r
-        }\r
-    }\r
-    \r
-    public boolean isPartial() {\r
-        return parameters.length < function.getBinding().getEffectiveArity();\r
-    }\r
-\r
-    /**\r
-     * Removes apply if it does not have parameters.\r
-     */\r
-    public void removeDegenerated() {\r
-        if(getParameters().length == 0) {\r
-            target.replaceBy(getFunction());\r
-            getFunction().remove();\r
-            detach();\r
-        }\r
-    }\r
-\r
-    public boolean determineGenerateOnFly() {\r
-        if(hasEffect())\r
-            return false;\r
-        ValRef ref = target.getOccurrence();\r
-        if(ref == null || ref.getNext() != null)\r
-            return false;\r
-        Object parent = ref.getParent();\r
-        if(parent instanceof SSAStatement) {\r
-            if(((SSAStatement)parent).getParent() != getParent())\r
-                return false;\r
-        }\r
-        else if(parent instanceof SSAExit) {\r
-            if(((SSAExit)parent).getParent() != getParent())\r
-                return false;\r
-            if(parent instanceof Switch)\r
-                return false;\r
-        }\r
-        else\r
-            return false;\r
-        return true;\r
-    }\r
-    \r
-    @Override\r
-    public void markGenerateOnFly() {        \r
-        target.generateOnFly = determineGenerateOnFly();\r
-    }\r
-\r
-    public ValRef getFunction() {\r
-        return function;\r
-    }\r
-\r
-    public void setFunction(ValRef function) {\r
-        this.function = function;\r
-        function.setParent(this);\r
-    }\r
-\r
-    public ValRef[] getParameters() {\r
-        return parameters;\r
-    }\r
-\r
-    public void setParameters(ValRef[] parameters) {\r
-        /*if(SCLCompilerConfiguration.DEBUG)\r
-            if(parameters.length == 0)\r
-                throw new InternalCompilerError();*/\r
-        this.parameters = parameters;\r
-        for(ValRef parameter : parameters)\r
-            parameter.setParent(this);\r
-    }\r
-    \r
-    @Override\r
-    public SSAStatement copy(CopyContext context) {\r
-        LetApply result = new LetApply(context.copy(target), \r
-                context.copyType(effect),\r
-                context.copy(function), \r
-                context.copy(parameters));\r
-        return result;\r
-    }\r
-    \r
-    @Override\r
-    public void replace(TVar[] vars, Type[] replacements) {\r
-        target.replace(vars, replacements);\r
-        function.replace(vars, replacements);\r
-        effect = effect.replace(vars, replacements);\r
-        for(ValRef parameter : parameters)\r
-            parameter.replace(vars, replacements);\r
-    }\r
-    \r
-    /**\r
-     * Inlines the application by the given function.\r
-     * It is assumed that the function has the same number\r
-     * of parameters as this one and there are no other \r
-     * references to the function (copy function before\r
-     * inlining if necessary).\r
-     */\r
-    public void inline(SSAFunction function) {\r
-        if(function.getArity() != parameters.length)\r
-            throw new InternalCompilerError();        \r
-               \r
-        SSABlock headBlock = getParent();\r
-        SSAFunction thisFunction = headBlock.getParent();\r
-               \r
-        /*System.out.println("--- INLINING -------------------------------");\r
-        System.out.println(thisFunction);\r
-        System.out.println("Function name: " + getFunction().getBinding());\r
-        System.out.println("++++++++++++++++++++++++++++++++++++++++++++");\r
-        System.out.println(function);   \r
-        */\r
-        \r
-        if(this.function.getTypeParameters().length > 0) {\r
-            /*if(function.getParent() != null) {\r
-                PrintingContext pc = new PrintingContext();\r
-                pc.append("----------------------------\n");\r
-                function.getParent().getParentFunction().toString(pc);\r
-                pc.append("\n----\n");\r
-                function.toString(pc);\r
-                pc.append("\n");\r
-                pc.append(function.getTypeParameters());\r
-                pc.append(" -> ");\r
-                pc.append(this.function.getTypeParameters());\r
-                System.out.println(pc.toString());\r
-            }*/\r
-            function.replace(function.getTypeParameters(), this.function.getTypeParameters());\r
-        }\r
-\r
-        if(getPrev() != null)\r
-            getPrev().setAsLastStatement();\r
-        else\r
-            headBlock.removeStatements();\r
-        \r
-        // Create tail block\r
-        SSABlock tailBlock = new SSABlock(new BoundVar[] {target});\r
-        thisFunction.addBlock(tailBlock);\r
-        {\r
-            SSAStatement stat = getNext();\r
-            while(stat != null) {\r
-                SSAStatement temp = stat.getNext();\r
-                tailBlock.addStatement(stat);\r
-                stat = temp;\r
-            }\r
-        }\r
-        tailBlock.setExit(headBlock.getExit());\r
-        \r
-        // Merge blocks        \r
-        thisFunction.mergeBlocks(function);           \r
-        \r
-        headBlock.setExit(new Jump(function.getFirstBlock().createOccurrence(), \r
-                parameters));\r
-        function.getReturnCont().replaceWith(tailBlock);\r
-\r
-        this.function.remove();\r
-        // Note: No need to remove or detach this statement anymore\r
-        \r
-        // TODO remove function\r
-        /*\r
-        System.out.println("============================================");\r
-        System.out.println(thisFunction);\r
-        */\r
-    }\r
-\r
-    @Override\r
-    public void collectFreeVariables(SSAFunction parentFunction,\r
-            ArrayList<ValRef> vars) {\r
-        function.collectFreeVariables(parentFunction, vars);\r
-        for(ValRef parameter : parameters)\r
-            parameter.collectFreeVariables(parentFunction, vars);\r
-    }\r
-    \r
-    @Override\r
-    public void replaceByApply(ValRef valRef, Val newFunction, Type[] typeParameters, Val[] parameters) {\r
-        if(function == valRef) {\r
-            valRef.remove();\r
-            setFunction(newFunction.createOccurrence(typeParameters));\r
-            setParameters(ValRef.concat(ValRef.createOccurrences(parameters), this.parameters));\r
-        }\r
-        else\r
-            super.replaceByApply(valRef, newFunction, typeParameters, parameters);\r
-    }\r
-\r
-    /**\r
-     * Splits this application into two applications where the first has\r
-     * the arity given as a parameter and the new application inserted \r
-     * after this statement has the rest of the parameters.\r
-     */\r
-    public void split(int arity) {\r
-        if(arity == parameters.length)\r
-            return;\r
-        if(arity > parameters.length)\r
-            throw new InternalCompilerError();\r
-        ValRef[] firstHalf = arity == 0 ? ValRef.EMPTY_ARRAY : Arrays.copyOf(parameters, arity);\r
-        ValRef[] secondHalf = arity == parameters.length ? ValRef.EMPTY_ARRAY : Arrays.copyOfRange(parameters, arity, parameters.length);\r
-        BoundVar newVar;\r
-        try {\r
-            MultiFunction mfun = Types.matchFunction(function.getType(), arity);\r
-            newVar = new BoundVar(mfun.returnType);\r
-        } catch (MatchException e) {\r
-            throw new InternalCompilerError();\r
-        }\r
-        LetApply newApply = new LetApply(target, effect, \r
-                newVar.createOccurrence(), secondHalf);\r
-        newApply.insertAfter(this);\r
-        effect = Types.NO_EFFECTS;\r
-        setTarget(newVar);\r
-        setParameters(firstHalf);\r
-    }\r
-    \r
-    /**\r
-     * True, if the application may have side effects.\r
-     */\r
-    public boolean hasEffect() {\r
-        return effect != Types.NO_EFFECTS;\r
-    }\r
-\r
-    public void updateEffect() {\r
-        try {\r
-            MultiFunction mFun = Types.matchFunction(function.getType(), parameters.length);\r
-            this.effect = mFun.effect;\r
-        } catch (MatchException e) {\r
-            throw new InternalCompilerError(e);\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public void prepare(MethodBuilder mb) {\r
-        function.getBinding().prepare(mb);\r
-    }\r
-}\r
+package org.simantics.scl.compiler.internal.codegen.ssa.statements;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.constants.SCLConstant;
+import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
+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.SSAExit;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.BoundVarBinder;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
+import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;
+import org.simantics.scl.compiler.internal.codegen.ssa.exits.Switch;
+import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
+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;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+import org.simantics.scl.compiler.types.util.MultiFunction;
+
+public class LetApply extends LetStatement implements ValRefBinder {
+    private ValRef function;
+    private ValRef[] parameters;
+    Type effect;
+    
+    public LetApply(BoundVar target, Type effect, ValRef function, ValRef ... parameters) {
+        super(target);
+        if(SCLCompilerConfiguration.DEBUG) {
+            if(effect == null)
+                throw new InternalCompilerError();
+            if(function.getBinding() == null)
+                throw new InternalCompilerError();
+        }
+        this.setFunction(function);
+        this.setParameters(parameters);
+        this.effect = Types.canonical(effect);
+    }
+
+    public void push(MethodBuilder mb) {
+        //mb.getCodeBuilder().mapLineNumber(lineNumber);
+        Val f = getFunction().getBinding();
+        Val[] ps = ValRef.getBindings(getParameters());
+        if(f instanceof Constant) {
+            Constant cf = (Constant)f;
+            Type returnType = cf.apply(mb, getFunction().getTypeParameters(), ps);
+            if(Types.isBoxed(returnType))
+                mb.unbox(target.getType());
+        }
+        else {            
+            mb.push(f, f.getType());
+            mb.pushBoxed(ps);
+            mb.genericApply(ps.length);
+            mb.unbox(target.getType());
+        }
+    }
+    
+    @Override
+    public void generateCode(MethodBuilder mb) {
+        if(!target.generateOnFly) {
+            push(mb);
+            mb.store(target);
+        }
+    }
+
+    @Override
+    public void toString(PrintingContext context) {
+        if(/*target.getLabel() == null &&*/ determineGenerateOnFly())
+            context.addInlineExpression(target, this);
+        else
+            toStringAux(context);
+    }
+    
+    private void toStringAux(PrintingContext context) {
+        context.indentation();
+        context.append(target);
+        context.append("(" + target.occurrenceCount() + ")");
+        context.append(" = ");
+        bodyToString(context);
+        context.append('\n');
+        
+    }
+    
+    public void bodyToString(PrintingContext context) {
+        if(context.getErrorMarker() == this)
+            context.append("!> ");
+        if(hasEffect()) {
+            context.append("<");
+            context.append(effect);
+            context.append("> ");
+        }
+        context.append(getFunction());
+        for(ValRef parameter : getParameters()) {
+            context.append(' ');
+            context.append(parameter);
+        }
+    }
+    
+    @Override
+    public String toString() {
+        PrintingContext context = new PrintingContext();
+        toStringAux(context);
+        return context.toString();
+    }
+
+    @Override
+    public void validate(SSAValidationContext context) {
+        context.validate(target);
+        if(target.getParent() != this)
+            throw new InternalCompilerError();
+        context.validate(function);
+        if(function.getParent() != this)
+            throw new InternalCompilerError();
+        for(ValRef parameter : parameters) {
+            context.validate(parameter);
+            if(parameter.getParent() != this)
+                throw new InternalCompilerError();
+        }
+        //if(parameters.length == 0)
+        //    throw new InternalCompilerError();
+        
+        
+        MultiFunction mFun;
+        try {
+            mFun = Types.matchFunction(getFunction().getType(), getParameters().length);
+        } catch (MatchException e) {
+            context.setErrorMarker(this);
+            throw new InternalCompilerError();
+        }
+        for(int i=0;i<getParameters().length;++i)
+            context.assertSubsumes(this, getParameters()[i].getType(), mFun.parameterTypes[i]);
+        context.assertSubsumes(this, target.getType(), mFun.returnType);
+        context.assertEqualsEffect(this, effect, mFun.effect);
+    }
+
+    @Override
+    public void destroy() {
+        getFunction().remove();
+        for(ValRef parameter : getParameters())
+            parameter.remove();
+    }
+    
+    @Override
+    public void simplify(SSASimplificationContext context) {
+        if(target.hasNoOccurences() && !hasEffect()) {
+            remove();
+            context.markModified("LetApply.dead-let-statement");
+            return;
+        }
+        // TODO this is quite heavy way for inlining constants
+        for(int i=0;i<parameters.length;++i) {
+            ValRef parameter = parameters[i];
+            Val value = parameter.getBinding();
+            if(!(value instanceof SCLConstant))
+                continue;
+            SCLConstant constant = (SCLConstant)value;
+            if(constant.inlineArity != 0)
+                continue;
+            SSAFunction definition = constant.definition;
+            SSABlock block = definition.getFirstBlock();
+            if(block.getFirstStatement() != null || !(block.getExit() instanceof Jump))
+                continue;
+            Jump jump = (Jump)block.getExit();
+            if(jump.getTarget().getBinding() != definition.getReturnCont())
+                continue;
+            if(jump.getParameter(0).getTypeParameters().length > 0)
+                continue;
+            parameter.replaceBy(jump.getParameter(0).getBinding());
+        }
+        Val functionVal = getFunction().getBinding();
+        if(functionVal instanceof BoundVar) {
+            BoundVarBinder parent_ = ((BoundVar)functionVal).parent;
+            if(parent_ instanceof SSAFunction) {
+                SSAFunction function = (SSAFunction)parent_;
+                if(functionVal.hasMoreThanOneOccurences())
+                    return;
+                if(getParameters().length < function.getArity())
+                    return;
+                if(getParameters().length > function.getArity())
+                    split(function.getArity());
+                inline(function);
+                function.detach();
+                context.markModified("LetApply.beta-lambda");
+            }
+            else if(parent_ instanceof LetApply) {
+                LetApply apply = (LetApply)parent_;
+                if(apply.hasEffect())
+                    return;
+                boolean hasJustOneOccurence = !functionVal.hasMoreThanOneOccurences();
+                if((hasJustOneOccurence && apply.getParent() == getParent()) ||
+                        apply.isPartial()) {
+                    if(hasJustOneOccurence) {
+                        apply.detach();
+                        setFunction(apply.getFunction());
+                        setParameters(ValRef.concat(apply.getParameters(), getParameters()));
+                    }
+                    else {
+                        setFunction(apply.getFunction().copy());
+                        setParameters(ValRef.concat(ValRef.copy(apply.getParameters()), getParameters()));
+                    }
+                    context.markModified("LetApply.merge-applications");
+                }
+            }
+            else if(parent_ instanceof SSABlock) {
+                SSABlock parent = getParent();
+                if(parent_ != parent)
+                    return;
+                if(parent.getFirstStatement() != this)
+                    return;
+                if(!parent.hasMoreThanOneOccurences())
+                    return; // We stop here, because situation can be handled by better transformations
+                if(functionVal.hasMoreThanOneOccurences())
+                    return;
+                // We have now the following situation:
+                //    [c] ... f ... =
+                //        x = f ... 
+                // * this application is the only reference to f
+                // * there are multiple references to [c]
+                for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext())
+                    if(!(ref.getParent() instanceof Jump))
+                        return;
+                
+                // Finds the position of the functionVal in the parameter list of 
+                // the parent block.
+                int position;
+                for(position=0;position<parent.getParameters().length;++position)
+                    if(parent.getParameters()[position] == functionVal)
+                        break;
+                if(position == parent.getParameters().length)
+                    throw new InternalCompilerError();
+                
+                // Do tranformation
+                for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext()) {
+                    Jump jump = (Jump)ref.getParent();
+                    SSABlock block = jump.getParent();
+                    
+                    BoundVar newTarget = new BoundVar(target.getType());
+                    block.addStatement(new LetApply(newTarget, effect, jump.getParameter(position), ValRef.copy(parameters)));
+                    jump.setParameter(position, newTarget.createOccurrence());
+                }
+                
+                parent.setParameter(position, target);
+                remove();
+                context.markModified("LetApply.hoist-apply");
+            }
+        }
+        else if(functionVal instanceof Constant) {
+            ((Constant)functionVal).inline(context, this);
+        }
+    }
+    
+    public boolean isPartial() {
+        return parameters.length < function.getBinding().getEffectiveArity();
+    }
+
+    /**
+     * Removes apply if it does not have parameters.
+     */
+    public void removeDegenerated() {
+        if(getParameters().length == 0) {
+            target.replaceBy(getFunction());
+            getFunction().remove();
+            detach();
+        }
+    }
+
+    public boolean determineGenerateOnFly() {
+        if(hasEffect())
+            return false;
+        ValRef ref = target.getOccurrence();
+        if(ref == null || ref.getNext() != null)
+            return false;
+        Object parent = ref.getParent();
+        if(parent instanceof SSAStatement) {
+            if(((SSAStatement)parent).getParent() != getParent())
+                return false;
+        }
+        else if(parent instanceof SSAExit) {
+            if(((SSAExit)parent).getParent() != getParent())
+                return false;
+            if(parent instanceof Switch)
+                return false;
+        }
+        else
+            return false;
+        return true;
+    }
+    
+    @Override
+    public void markGenerateOnFly() {        
+        target.generateOnFly = determineGenerateOnFly();
+    }
+
+    public ValRef getFunction() {
+        return function;
+    }
+
+    public void setFunction(ValRef function) {
+        this.function = function;
+        function.setParent(this);
+    }
+
+    public ValRef[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(ValRef[] parameters) {
+        /*if(SCLCompilerConfiguration.DEBUG)
+            if(parameters.length == 0)
+                throw new InternalCompilerError();*/
+        this.parameters = parameters;
+        for(ValRef parameter : parameters)
+            parameter.setParent(this);
+    }
+    
+    @Override
+    public SSAStatement copy(CopyContext context) {
+        LetApply result = new LetApply(context.copy(target), 
+                context.copyType(effect),
+                context.copy(function), 
+                context.copy(parameters));
+        return result;
+    }
+    
+    @Override
+    public void replace(TVar[] vars, Type[] replacements) {
+        target.replace(vars, replacements);
+        function.replace(vars, replacements);
+        effect = effect.replace(vars, replacements);
+        for(ValRef parameter : parameters)
+            parameter.replace(vars, replacements);
+    }
+    
+    /**
+     * Inlines the application by the given function.
+     * It is assumed that the function has the same number
+     * of parameters as this one and there are no other 
+     * references to the function (copy function before
+     * inlining if necessary).
+     */
+    public void inline(SSAFunction function) {
+        if(function.getArity() != parameters.length)
+            throw new InternalCompilerError();        
+               
+        SSABlock headBlock = getParent();
+        SSAFunction thisFunction = headBlock.getParent();
+               
+        /*System.out.println("--- INLINING -------------------------------");
+        System.out.println(thisFunction);
+        System.out.println("Function name: " + getFunction().getBinding());
+        System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
+        System.out.println(function);   
+        */
+        
+        if(this.function.getTypeParameters().length > 0) {
+            /*if(function.getParent() != null) {
+                PrintingContext pc = new PrintingContext();
+                pc.append("----------------------------\n");
+                function.getParent().getParentFunction().toString(pc);
+                pc.append("\n----\n");
+                function.toString(pc);
+                pc.append("\n");
+                pc.append(function.getTypeParameters());
+                pc.append(" -> ");
+                pc.append(this.function.getTypeParameters());
+                System.out.println(pc.toString());
+            }*/
+            function.replace(function.getTypeParameters(), this.function.getTypeParameters());
+        }
+
+        if(getPrev() != null)
+            getPrev().setAsLastStatement();
+        else
+            headBlock.removeStatements();
+        
+        // Create tail block
+        SSABlock tailBlock = new SSABlock(new BoundVar[] {target});
+        thisFunction.addBlock(tailBlock);
+        {
+            SSAStatement stat = getNext();
+            while(stat != null) {
+                SSAStatement temp = stat.getNext();
+                tailBlock.addStatement(stat);
+                stat = temp;
+            }
+        }
+        tailBlock.setExit(headBlock.getExit());
+        
+        // Merge blocks        
+        thisFunction.mergeBlocks(function);
+        
+        headBlock.setExit(new Jump(function.getFirstBlock().createOccurrence(), 
+                parameters));
+        function.getReturnCont().replaceWith(tailBlock);
+
+        this.function.remove();
+        // Note: No need to remove or detach this statement anymore
+        
+        // TODO remove function
+        /*
+        System.out.println("============================================");
+        System.out.println(thisFunction);
+        */
+    }
+
+    @Override
+    public void collectFreeVariables(SSAFunction parentFunction,
+            ArrayList<ValRef> vars) {
+        function.collectFreeVariables(parentFunction, vars);
+        for(ValRef parameter : parameters)
+            parameter.collectFreeVariables(parentFunction, vars);
+    }
+    
+    @Override
+    public void replaceByApply(ValRef valRef, Val newFunction, Type[] typeParameters, Val[] parameters) {
+        if(function == valRef) {
+            valRef.remove();
+            setFunction(newFunction.createOccurrence(typeParameters));
+            setParameters(ValRef.concat(ValRef.createOccurrences(parameters), this.parameters));
+        }
+        else
+            super.replaceByApply(valRef, newFunction, typeParameters, parameters);
+    }
+
+    /**
+     * Splits this application into two applications where the first has
+     * the arity given as a parameter and the new application inserted 
+     * after this statement has the rest of the parameters.
+     */
+    public void split(int arity) {
+        if(arity == parameters.length)
+            return;
+        if(arity > parameters.length)
+            throw new InternalCompilerError();
+        ValRef[] firstHalf = arity == 0 ? ValRef.EMPTY_ARRAY : Arrays.copyOf(parameters, arity);
+        ValRef[] secondHalf = arity == parameters.length ? ValRef.EMPTY_ARRAY : Arrays.copyOfRange(parameters, arity, parameters.length);
+        BoundVar newVar;
+        try {
+            MultiFunction mfun = Types.matchFunction(function.getType(), arity);
+            newVar = new BoundVar(mfun.returnType);
+        } catch (MatchException e) {
+            throw new InternalCompilerError();
+        }
+        LetApply newApply = new LetApply(target, effect, 
+                newVar.createOccurrence(), secondHalf);
+        newApply.insertAfter(this);
+        effect = Types.NO_EFFECTS;
+        setTarget(newVar);
+        setParameters(firstHalf);
+    }
+    
+    /**
+     * True, if the application may have side effects.
+     */
+    public boolean hasEffect() {
+        return effect != Types.NO_EFFECTS;
+    }
+
+    public void updateEffect() {
+        try {
+            MultiFunction mFun = Types.matchFunction(function.getType(), parameters.length);
+            this.effect = mFun.effect;
+        } catch (MatchException e) {
+            throw new InternalCompilerError(e);
+        }
+    }
+    
+    @Override
+    public void prepare(MethodBuilder mb) {
+        function.getBinding().prepare(mb);
+    }
+
+    @Override
+    public void forValRefs(ValRefVisitor visitor) {
+        visitor.visit(function);
+        for(ValRef parameter : parameters)
+            visitor.visit(parameter);
+    }
+}