]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSABlock.java
(refs #7250) Merging master, minor CHR bugfixes
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / SSABlock.java
index 405e31ddd083be4451d77f0d93c6bcb2a0e7d1d2..ba9d62d27ce730bffc2b99772321406736125e07 100644 (file)
-package org.simantics.scl.compiler.internal.codegen.ssa;\r
-\r
-import java.util.ArrayList;\r
-\r
-import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
-import org.simantics.scl.compiler.constants.Constant;\r
-import org.simantics.scl.compiler.constants.SCLConstant;\r
-import org.simantics.scl.compiler.internal.codegen.continuations.BranchRef;\r
-import org.simantics.scl.compiler.internal.codegen.continuations.Cont;\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.binders.BoundVarBinder;\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.ssa.statements.LetApply;\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.Printable;\r
-import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;\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.internal.codegen.utils.ValRefVisitor;\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
-\r
-public final class SSABlock extends Cont implements Printable, BoundVarBinder {\r
-    public static final SSABlock[] EMPTY_ARRAY = new SSABlock[0];\r
-    \r
-    BoundVar[] parameters;\r
-    \r
-    SSAFunction parent;\r
-    SSABlock prev;\r
-    SSABlock next;\r
-    SSAStatement firstStatement;\r
-    SSAStatement lastStatement;\r
-    SSAExit exit;\r
-    \r
-    public SSABlock(Type ... parameterTypes) {\r
-        parameters = new BoundVar[parameterTypes.length];\r
-        for(int i=0;i<parameterTypes.length;++i) {\r
-            BoundVar parameter = new BoundVar(parameterTypes[i]); \r
-            parameters[i] = parameter;\r
-            parameter.parent = this;\r
-        }\r
-    }\r
-    \r
-    public SSABlock(BoundVar[] parameters) {    \r
-        this.parameters = parameters;\r
-        for(BoundVar parameter : parameters)\r
-            parameter.parent = this;\r
-    }\r
-\r
-    public SSAFunction getParent() {\r
-        return parent;\r
-    }\r
-    \r
-    public SSABlock getNext() {\r
-        return next;\r
-    }\r
-    \r
-    public SSABlock getPrev() {\r
-        return prev;\r
-    }\r
-    \r
-    public SSAExit getExit() {\r
-        return exit;\r
-    }\r
-    \r
-    public void removeStatements() {\r
-        this.firstStatement = null;\r
-        this.lastStatement = null; \r
-    }\r
-    \r
-    @Override\r
-    public int getArity() {\r
-        return parameters.length;\r
-    }\r
-    \r
-    public int getStatementCount() {\r
-        int count = 0;\r
-        for(SSAStatement stat = firstStatement;stat != null;stat = stat.next)\r
-            ++count;\r
-        return count;\r
-    }\r
-    \r
-    @Override\r
-    public Type getParameterType(int parameterId) {\r
-        return parameters[parameterId].getType();\r
-    }\r
-    \r
-    public Type[] getParameterTypes() {\r
-        return Types.getTypes(parameters);\r
-    }\r
-    \r
-    public BoundVar[] getParameters() {\r
-        return parameters;\r
-    }\r
-    \r
-    public void setExit(SSAExit exit) {\r
-        this.exit = exit;\r
-        exit.parent = this;\r
-    }\r
-\r
-    public void detach() {\r
-        if(prev == null)\r
-            parent.firstBlock = next;\r
-        else\r
-            prev.next = next;\r
-        if(next == null)\r
-            parent.lastBlock = prev;\r
-        else\r
-            next.prev = prev;\r
-        if(parent.firstBlock == null)\r
-            throw new InternalCompilerError();\r
-    }\r
-\r
-    public void remove() {\r
-        detach();\r
-        destroy();\r
-    }\r
-    \r
-    public void destroy() {\r
-        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next)\r
-            statement.destroy();\r
-        exit.destroy();\r
-    }\r
-\r
-    public void addStatement(SSAStatement stat) {\r
-        if(SCLCompilerConfiguration.DEBUG) {\r
-            if((firstStatement == null) != (lastStatement == null))\r
-                throw new InternalCompilerError();\r
-        }\r
-        stat.parent = this;\r
-        if(lastStatement == null) {\r
-            firstStatement = lastStatement = stat;\r
-            stat.next = stat.prev = null;            \r
-        }\r
-        else {\r
-            lastStatement.next = stat;\r
-            stat.prev = lastStatement;\r
-            stat.next = null;\r
-            lastStatement = stat;\r
-        }\r
-    }\r
-    \r
-    public void generateCode(MethodBuilder mb) {\r
-        mb.setLocation(this);\r
-        for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)\r
-            stat.generateCode(mb);\r
-        exit.generateCode(mb);\r
-    }\r
-\r
-    public void toString(PrintingContext context) {\r
-        context.indentation();\r
-        context.append(this);\r
-        context.append("(" + occurrenceCount() + ")");\r
-        parametersToString(context);\r
-        context.append(" =\n");\r
-        bodyToString(context);\r
-    }\r
-    \r
-    public void parametersToString(PrintingContext context) {\r
-        for(BoundVar parameter : parameters) {\r
-            context.append(' ');\r
-            if(parameter.hasNoOccurences()) {\r
-                context.append('(');\r
-                context.append('_');\r
-                context.append(" :: ");\r
-                context.append(parameter.getType());\r
-                context.append(')');\r
-            }\r
-            else {\r
-                context.append('(');\r
-                context.append(parameter);\r
-                context.append(" :: ");\r
-                context.append(parameter.getType());\r
-                context.append(')');\r
-            }\r
-        }\r
-    }\r
-    \r
-    public void bodyToString(PrintingContext context) {\r
-        context.indent();\r
-        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next)\r
-            statement.toString(context);\r
-        context.indentation();\r
-        exit.toString(context);\r
-        context.dedent();\r
-    }\r
-\r
-    public void validate(SSAValidationContext context) {\r
-        if(exit.getParent() != this)\r
-            throw new InternalCompilerError();\r
-        for(BoundVar parameter : parameters) {         \r
-            context.validate(parameter);\r
-            if(parameter.parent != this)\r
-                throw new InternalCompilerError();\r
-        }\r
-        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next) {\r
-            if(statement.getParent() != this)\r
-                throw new InternalCompilerError();\r
-            statement.validate(context);\r
-        }\r
-        exit.validate(context);\r
-                \r
-        {\r
-            SSAStatement last = firstStatement;\r
-            if(last != null) {\r
-                while(last.next != null)\r
-                    last = last.next;\r
-            }\r
-            if(last != lastStatement)\r
-                throw new InternalCompilerError();\r
-        }\r
-    }\r
-\r
-    public void simplify(SSASimplificationContext context) {\r
-        if(hasNoOccurences() && parent.firstBlock != this) {\r
-            remove();\r
-            context.markModified("dead-block");\r
-            return;\r
-        }\r
-        \r
-        tryToImproveParameters(context);\r
-        \r
-        // Simplify statements and exit\r
-        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next)\r
-            statement.simplify(context);\r
-        exit.simplify(context);\r
-        \r
-        // Simplifications to this block\r
-        if(exit instanceof Switch) {\r
-            if(simplifySwitch()) {\r
-                context.markModified("beta-switch");\r
-            }\r
-        }\r
-        if(exit instanceof Jump) {\r
-            if(firstStatement == null && parent.firstBlock != this) {\r
-                if(etaBlock(context)) {\r
-                    context.markModified("eta-block");\r
-                    return;\r
-                }\r
-                else if(inlineJump()) {\r
-                    context.markModified("beta-block");\r
-                    return;\r
-                }\r
-            }\r
-            else {\r
-                if(optimizeTailSelfCall()) {\r
-                    context.markModified("simplify-tail-call");\r
-                    return;\r
-                }\r
-                else if(inlineJump()) {\r
-                    context.markModified("beta-block");\r
-                    return;\r
-                }\r
-            }\r
-        }        \r
-    }\r
-\r
-    private void tryToImproveParameters(SSASimplificationContext context) {\r
-        if(parent.firstBlock == this)\r
-            return;\r
-        if(parameters.length == 0)\r
-            return;\r
-        for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext())\r
-            if(!(ref.getParent() instanceof Jump))\r
-                return;\r
-        boolean modified = false;\r
-        for(int i=0;i<parameters.length;++i)\r
-            if(tryToImproveParameter(i)) {\r
-                --i;\r
-                modified = true;\r
-            }\r
-        if(modified)\r
-            context.markModified("improve-parameters");\r
-    }\r
-\r
-    private boolean tryToImproveParameter(int position) {\r
-        BoundVar parameter = parameters[position];\r
-        Val constant = null;\r
-        ValRef constantRef = null;\r
-        for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext()) {\r
-            Jump jump = (Jump)ref.getParent();\r
-            ValRef valRef = jump.getParameters()[position];\r
-            Val val = valRef.getBinding();\r
-            if(val == parameter)\r
-                continue;\r
-            if(constant == null) {\r
-                constant = val;\r
-                constantRef = valRef;\r
-                continue;\r
-            }\r
-            if(val != constant)\r
-                return false;\r
-        }\r
-        if(constant == null)\r
-            return false; // This is a strange case, because we cannot get the parameter anywhere\r
-        parameter.replaceBy(constantRef);\r
-        \r
-        for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext()) {\r
-            Jump jump = (Jump)ref.getParent();\r
-            jump.setParameters(removeAt(jump.getParameters(), position));\r
-        }\r
-        \r
-        parameters = removeAt(parameters, position);\r
-        return true;\r
-    }\r
-    \r
-    private static BoundVar[] removeAt(BoundVar[] vars, int pos) {\r
-        BoundVar[] result = new BoundVar[vars.length-1];\r
-        for(int i=0;i<pos;++i)\r
-            result[i] = vars[i];\r
-        for(int i=pos+1;i<vars.length;++i)\r
-            result[i-1] = vars[i];\r
-        return result;\r
-    }\r
-\r
-    private static ValRef[] removeAt(ValRef[] vars, int pos) {\r
-        ValRef[] result = new ValRef[vars.length-1];\r
-        for(int i=0;i<pos;++i)\r
-            result[i] = vars[i];\r
-        vars[pos].remove();\r
-        for(int i=pos+1;i<vars.length;++i)\r
-            result[i-1] = vars[i];\r
-        return result;\r
-    }\r
-    \r
-    private boolean optimizeTailSelfCall() {\r
-        Jump jump = (Jump)exit;\r
-        if(jump.getTarget().getBinding() != parent.returnCont)\r
-            return false;\r
-        if(jump.getParameters().length != 1)\r
-            return false;\r
-        if(lastStatement == null || !(lastStatement instanceof LetApply))\r
-            return false;\r
-        LetApply apply = (LetApply)lastStatement;\r
-        SSABlock initialBlock = parent.firstBlock;\r
-        if(initialBlock.parameters.length != apply.getParameters().length)\r
-            return false;\r
-        Val function = apply.getFunction().getBinding();\r
-        if(function != parent.target)\r
-            return false;\r
-        \r
-        // Do modifications\r
-        apply.detach();\r
-        apply.getFunction().remove();\r
-        jump.getTarget().remove();\r
-        jump.setTarget(initialBlock.createOccurrence());\r
-        jump.setParameters(apply.getParameters());\r
-        \r
-        return true;\r
-    }\r
-\r
-    private boolean etaBlock(SSASimplificationContext context) {\r
-        Jump jump = (Jump)exit;\r
-        if(parameters.length != jump.getParameters().length)\r
-            return false;\r
-        for(int i=0;i<parameters.length;++i)\r
-            if(parameters[i] != jump.getParameters()[i].getBinding() ||\r
-               parameters[i].hasMoreThanOneOccurences())\r
-                return false;\r
-        \r
-        replaceWith(jump.getTarget().getBinding());\r
-        remove();\r
-        return true;\r
-    }\r
-    \r
-    private boolean simplifySwitch() {\r
-        Switch sw = (Switch)exit;\r
-        ValRef scrutineeRef = sw.getScrutinee();\r
-        Val scrutinee = scrutineeRef.getBinding();\r
-        if(scrutinee instanceof BoundVar) {\r
-            BoundVarBinder parent = ((BoundVar)scrutinee).parent;\r
-            if(!(parent instanceof LetApply))\r
-                return false;\r
-            LetApply apply = (LetApply)parent;\r
-            Val function = apply.getFunction().getBinding();\r
-            if(!(function instanceof Constant) || function instanceof SCLConstant)\r
-                return false;\r
-            for(BranchRef branch : sw.getBranches()) {\r
-                if(branch.constructor == function) {\r
-                    sw.destroy();\r
-                    setExit(new Jump(branch.cont.getBinding().createOccurrence(), \r
-                            ValRef.copy(apply.getParameters())));\r
-                    return true;\r
-                }\r
-            }\r
-        }\r
-        else if(scrutinee instanceof Constant) {\r
-            if(sw.getBranches().length == 1) {\r
-                BranchRef branch = sw.getBranches()[0];\r
-                if(branch.constructor == scrutinee) {\r
-                    /**\r
-                     * Optimizes for example\r
-                     *      switch ()\r
-                     *          () -> [a]\r
-                     * ===>\r
-                     *      [a]\r
-                     */\r
-                    sw.destroy();\r
-                    setExit(new Jump(branch.cont.getBinding().createOccurrence()));\r
-                }\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-    \r
-    private boolean inlineJump() {\r
-        Jump jump = (Jump)exit;\r
-        Cont target = jump.getTarget().getBinding();\r
-        if(!(target instanceof SSABlock))\r
-            return false;\r
-        if(target.hasMoreThanOneOccurences())\r
-            return false;\r
-        SSABlock block = (SSABlock)target;\r
-        if(block == parent.firstBlock || block == this)\r
-            return false;\r
-        \r
-        /*System.out.println(">> BEFORE INLINE >>");\r
-        System.out.println(getParent());\r
-        System.out.println(">> THIS BLOCK >>");\r
-        System.out.println(this);\r
-        System.out.println(">> TARGET BLOCK >>");\r
-        System.out.println(block);*/\r
-                \r
-        mergeStatements(block);\r
-\r
-        for(int i=0;i<jump.getParameters().length;++i)\r
-            block.parameters[i].replaceBy(jump.getParameters()[i]);\r
-        block.detach();\r
-        \r
-        jump.destroy();\r
-        setExit(block.exit);       \r
-        \r
-        /*System.out.println(">> AFTER INLINE >>");\r
-        System.out.println(getParent());\r
-        System.out.println(">> THIS BLOCK >>");\r
-        System.out.println(this);\r
-        System.out.println(">>>>>>>>>>>>>>>>>>");*/\r
-        return true;\r
-    }\r
-    \r
-    private void mergeStatements(SSABlock block) {\r
-        if(SCLCompilerConfiguration.DEBUG) {\r
-            SSAStatement last = firstStatement;\r
-            if(last != null) {\r
-                while(last.next != null)\r
-                    last = last.next;\r
-            }\r
-            if(last != lastStatement)\r
-                throw new InternalCompilerError();\r
-        }\r
-        SSAStatement stat = block.firstStatement;\r
-        while(stat != null) {\r
-            SSAStatement next = stat.next;\r
-            addStatement(stat);\r
-            stat = next;\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public String toString() {\r
-        PrintingContext context = new PrintingContext();\r
-        toString(context);\r
-        return context.toString();\r
-    }\r
-\r
-    public void markGenerateOnFly() {\r
-        for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)\r
-            stat.markGenerateOnFly();        \r
-    }\r
-    \r
-    public SSABlock copy(CopyContext context) {\r
-        SSABlock newBlock = new SSABlock(context.copy(parameters));\r
-        context.put(this, newBlock);\r
-        for(SSAStatement statement = firstStatement;\r
-                statement != null; statement = statement.next)\r
-            newBlock.addStatement(statement.copy(context));\r
-        newBlock.setExit(exit.copy(context)); \r
-        return newBlock;\r
-    }\r
-\r
-    public void setParameters(BoundVar[] parameters) {\r
-        for(BoundVar parameter : parameters)\r
-            parameter.parent = this;\r
-        this.parameters = parameters;\r
-    }\r
-\r
-    @Override\r
-    public void replace(TVar[] vars, Type[] replacements) {\r
-        for(BoundVar parameter : parameters)\r
-            parameter.replace(vars, replacements);\r
-        for(SSAStatement statement = firstStatement;\r
-                statement != null; statement = statement.next)\r
-            statement.replace(vars, replacements);\r
-        exit.replace(vars, replacements);\r
-    }\r
-\r
-    public void collectFreeVariables(SSAFunction function, ArrayList<ValRef> vars) {\r
-        for(SSAStatement statement = firstStatement;\r
-                statement != null; statement = statement.next)\r
-            statement.collectFreeVariables(function, vars);\r
-        exit.collectFreeVariables(function, vars);\r
-    }\r
-\r
-    @Override\r
-    public SSAFunction getParentFunction() {\r
-        return parent;\r
-    }\r
-\r
-    public void lambdaLift(SSALambdaLiftingContext context) {\r
-        for(SSAStatement statement = firstStatement;\r
-                statement != null; statement = statement.next)\r
-            statement.lambdaLift(context);\r
-    }\r
-    \r
-    public SSAStatement getFirstStatement() {\r
-        return firstStatement;\r
-    }\r
-\r
-    public void setParameter(int position, BoundVar target) {\r
-        parameters[position] = target;\r
-        target.parent = this;\r
-    }\r
-\r
-    public void prepare(MethodBuilder mb) {\r
-        for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)\r
-            stat.prepare(mb);\r
-        exit.prepare(mb);\r
-    }\r
-\r
-    public void forValRefs(ValRefVisitor visitor) {\r
-        for(SSAStatement statement = firstStatement;\r
-                statement != null; statement = statement.next)\r
-            statement.forValRefs(visitor);\r
-        exit.forValRefs(visitor);\r
-    }\r
-    \r
-}\r
+package org.simantics.scl.compiler.internal.codegen.ssa;
+
+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;
+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.binders.BoundVarBinder;
+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.ssa.statements.LetApply;
+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.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;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+public final class SSABlock extends Cont implements Printable, BoundVarBinder {
+    public static final SSABlock[] EMPTY_ARRAY = new SSABlock[0];
+    
+    BoundVar[] parameters;
+    
+    SSAFunction parent;
+    SSABlock prev;
+    SSABlock next;
+    SSAStatement firstStatement;
+    SSAStatement lastStatement;
+    SSAExit exit;
+    
+    public SSABlock(Type ... parameterTypes) {
+        parameters = new BoundVar[parameterTypes.length];
+        for(int i=0;i<parameterTypes.length;++i) {
+            BoundVar parameter = new BoundVar(parameterTypes[i]); 
+            parameters[i] = parameter;
+            parameter.parent = this;
+        }
+    }
+    
+    public SSABlock(BoundVar[] parameters) {    
+        this.parameters = parameters;
+        for(BoundVar parameter : parameters)
+            parameter.parent = this;
+    }
+
+    public SSAFunction getParent() {
+        return parent;
+    }
+    
+    public SSABlock getNext() {
+        return next;
+    }
+    
+    public SSABlock getPrev() {
+        return prev;
+    }
+    
+    public SSAExit getExit() {
+        return exit;
+    }
+    
+    public void removeStatements() {
+        this.firstStatement = null;
+        this.lastStatement = null; 
+    }
+    
+    @Override
+    public int getArity() {
+        return parameters.length;
+    }
+    
+    public int getStatementCount() {
+        int count = 0;
+        for(SSAStatement stat = firstStatement;stat != null;stat = stat.next)
+            ++count;
+        return count;
+    }
+    
+    @Override
+    public Type getParameterType(int parameterId) {
+        return parameters[parameterId].getType();
+    }
+    
+    public Type[] getParameterTypes() {
+        return Types.getTypes(parameters);
+    }
+    
+    public BoundVar[] getParameters() {
+        return parameters;
+    }
+    
+    public void setExit(SSAExit exit) {
+        this.exit = exit;
+        exit.parent = this;
+    }
+
+    public void detach() {
+        if(prev == null)
+            parent.firstBlock = next;
+        else
+            prev.next = next;
+        if(next == null)
+            parent.lastBlock = prev;
+        else
+            next.prev = prev;
+        if(parent.firstBlock == null)
+            throw new InternalCompilerError();
+    }
+
+    public void remove() {
+        detach();
+        destroy();
+    }
+    
+    public void destroy() {
+        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next)
+            statement.destroy();
+        exit.destroy();
+    }
+
+    public void addStatement(SSAStatement stat) {
+        if(SCLCompilerConfiguration.DEBUG) {
+            if((firstStatement == null) != (lastStatement == null))
+                throw new InternalCompilerError();
+        }
+        stat.parent = this;
+        if(lastStatement == null) {
+            firstStatement = lastStatement = stat;
+            stat.next = stat.prev = null;            
+        }
+        else {
+            lastStatement.next = stat;
+            stat.prev = lastStatement;
+            stat.next = null;
+            lastStatement = stat;
+        }
+    }
+    
+    public void generateCode(MethodBuilder mb) {
+        mb.setLocation(this);
+        for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)
+            stat.generateCode(mb);
+        exit.generateCode(mb);
+    }
+
+    public void toString(PrintingContext context) {
+        context.indentation();
+        context.append(this);
+        context.append("(" + occurrenceCount() + ")");
+        parametersToString(context);
+        context.append(" =\n");
+        bodyToString(context);
+    }
+    
+    public void parametersToString(PrintingContext context) {
+        for(BoundVar parameter : parameters) {
+            context.append(' ');
+            if(parameter.hasNoOccurences()) {
+                context.append('(');
+                context.append('_');
+                context.append(" :: ");
+                context.append(parameter.getType());
+                context.append(')');
+            }
+            else {
+                context.append('(');
+                context.append(parameter);
+                context.append(" :: ");
+                context.append(parameter.getType());
+                context.append(')');
+            }
+        }
+    }
+    
+    public void bodyToString(PrintingContext context) {
+        context.indent();
+        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next)
+            statement.toString(context);
+        context.indentation();
+        exit.toString(context);
+        context.dedent();
+    }
+
+    public void validate(SSAValidationContext context) {
+        if(exit.getParent() != this)
+            throw new InternalCompilerError();
+        for(BoundVar parameter : parameters) {         
+            context.validate(parameter);
+            if(parameter.parent != this)
+                throw new InternalCompilerError();
+        }
+        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next) {
+            if(statement.getParent() != this)
+                throw new InternalCompilerError();
+            statement.validate(context);
+        }
+        exit.validate(context);
+                
+        {
+            SSAStatement last = firstStatement;
+            if(last != null) {
+                while(last.next != null)
+                    last = last.next;
+            }
+            if(last != lastStatement)
+                throw new InternalCompilerError();
+        }
+    }
+
+    public void simplify(SSASimplificationContext context) {
+        if(hasNoOccurences() && parent.firstBlock != this) {
+            remove();
+            context.markModified("dead-block");
+            return;
+        }
+        
+        tryToImproveParameters(context);
+        
+        // Simplify statements and exit
+        for(SSAStatement statement = firstStatement; statement != null; statement = statement.next)
+            statement.simplify(context);
+        exit.simplify(context);
+        
+        // Simplifications to this block
+        if(exit instanceof Switch) {
+            if(simplifySwitch()) {
+                context.markModified("beta-switch");
+            }
+        }
+        if(exit instanceof Jump) {
+            if(firstStatement == null && parent.firstBlock != this) {
+                if(etaBlock(context)) {
+                    context.markModified("eta-block");
+                    return;
+                }
+                else if(inlineJump()) {
+                    context.markModified("beta-block");
+                    return;
+                }
+            }
+            else {
+                if(optimizeTailSelfCall()) {
+                    context.markModified("simplify-tail-call");
+                    return;
+                }
+                else if(inlineJump()) {
+                    context.markModified("beta-block");
+                    return;
+                }
+            }
+        }        
+    }
+
+    private void tryToImproveParameters(SSASimplificationContext context) {
+        if(parent.firstBlock == this)
+            return;
+        if(parameters.length == 0)
+            return;
+        for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext())
+            if(!(ref.getParent() instanceof Jump))
+                return;
+        boolean modified = false;
+        for(int i=0;i<parameters.length;++i)
+            if(tryToImproveParameter(i)) {
+                --i;
+                modified = true;
+            }
+        if(modified)
+            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];
+        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(constant == null)
+                return false; // This is a strange case, because we cannot get the parameter anywhere
+            parameter.replaceBy(constantRef);
+        }
+        else {
+            parameter.replaceBy(onlyPossibleValue);
+        }
+        
+        for(ContRef ref = getOccurrence(); ref != null; ref = ref.getNext()) {
+            Jump jump = (Jump)ref.getParent();
+            jump.setParameters(removeAt(jump.getParameters(), position));
+        }
+        
+        parameters = removeAt(parameters, position);
+        return true;
+    }
+    
+    private static BoundVar[] removeAt(BoundVar[] vars, int pos) {
+        BoundVar[] result = new BoundVar[vars.length-1];
+        for(int i=0;i<pos;++i)
+            result[i] = vars[i];
+        for(int i=pos+1;i<vars.length;++i)
+            result[i-1] = vars[i];
+        return result;
+    }
+
+    private static ValRef[] removeAt(ValRef[] vars, int pos) {
+        ValRef[] result = new ValRef[vars.length-1];
+        for(int i=0;i<pos;++i)
+            result[i] = vars[i];
+        vars[pos].remove();
+        for(int i=pos+1;i<vars.length;++i)
+            result[i-1] = vars[i];
+        return result;
+    }
+    
+    /*
+     * This method assumes that the exit of the block is Jump.
+     */
+    private boolean optimizeTailSelfCall() {
+        // 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;
+        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)
+            return false;
+        for(int i=0;i<parameters.length;++i)
+            if(parameters[i] != jump.getParameters()[i].getBinding() ||
+               parameters[i].hasMoreThanOneOccurences())
+                return false;
+        
+        replaceWith(jump.getTarget().getBinding());
+        remove();
+        return true;
+    }
+    
+    private boolean simplifySwitch() {
+        Switch sw = (Switch)exit;
+        ValRef scrutineeRef = sw.getScrutinee();
+        Val scrutinee = scrutineeRef.getBinding();
+        if(scrutinee instanceof BoundVar) {
+            BoundVarBinder parent = ((BoundVar)scrutinee).parent;
+            if(!(parent instanceof LetApply))
+                return false;
+            LetApply apply = (LetApply)parent;
+            Val function = apply.getFunction().getBinding();
+            if(!(function instanceof Constant) || function instanceof SCLConstant)
+                return false;
+            for(BranchRef branch : sw.getBranches()) {
+                if(branch.constructor == function) {
+                    sw.destroy();
+                    setExit(new Jump(branch.cont.getBinding().createOccurrence(), 
+                            ValRef.copy(apply.getParameters())));
+                    return true;
+                }
+            }
+        }
+        else if(scrutinee instanceof Constant) {
+            if(sw.getBranches().length == 1) {
+                BranchRef branch = sw.getBranches()[0];
+                if(branch.constructor == scrutinee) {
+                    /**
+                     * Optimizes for example
+                     *      switch ()
+                     *          () -> [a]
+                     * ===>
+                     *      [a]
+                     */
+                    sw.destroy();
+                    setExit(new Jump(branch.cont.getBinding().createOccurrence()));
+                }
+            }
+        }
+        return false;
+    }
+    
+    private boolean inlineJump() {
+        Jump jump = (Jump)exit;
+        Cont target = jump.getTarget().getBinding();
+        if(!(target instanceof SSABlock))
+            return false;
+        if(target.hasMoreThanOneOccurences())
+            return false;
+        SSABlock block = (SSABlock)target;
+        if(block == parent.firstBlock || block == this)
+            return false;
+        
+        /*System.out.println(">> BEFORE INLINE >>");
+        System.out.println(getParent());
+        System.out.println(">> THIS BLOCK >>");
+        System.out.println(this);
+        System.out.println(">> TARGET BLOCK >>");
+        System.out.println(block);*/
+                
+        mergeStatements(block);
+
+        for(int i=0;i<jump.getParameters().length;++i)
+            block.parameters[i].replaceBy(jump.getParameters()[i]);
+        block.detach();
+        
+        jump.destroy();
+        setExit(block.exit);
+        
+        /*System.out.println(">> AFTER INLINE >>");
+        System.out.println(getParent());
+        System.out.println(">> THIS BLOCK >>");
+        System.out.println(this);
+        System.out.println(">>>>>>>>>>>>>>>>>>");*/
+        return true;
+    }
+    
+    private void mergeStatements(SSABlock block) {
+        if(SCLCompilerConfiguration.DEBUG) {
+            SSAStatement last = firstStatement;
+            if(last != null) {
+                while(last.next != null)
+                    last = last.next;
+            }
+            if(last != lastStatement)
+                throw new InternalCompilerError();
+        }
+        SSAStatement stat = block.firstStatement;
+        while(stat != null) {
+            SSAStatement next = stat.next;
+            addStatement(stat);
+            stat = next;
+        }
+    }
+
+    @Override
+    public String toString() {
+        PrintingContext context = new PrintingContext();
+        toString(context);
+        return context.toString();
+    }
+
+    public void markGenerateOnFly() {
+        for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)
+            stat.markGenerateOnFly();
+    }
+    
+    public SSABlock copy(CopyContext context) {
+        SSABlock newBlock = new SSABlock(context.copy(parameters));
+        context.put(this, newBlock);
+        for(SSAStatement statement = firstStatement;
+                statement != null; statement = statement.next)
+            newBlock.addStatement(statement.copy(context));
+        newBlock.setExit(exit.copy(context)); 
+        return newBlock;
+    }
+
+    public void setParameters(BoundVar[] parameters) {
+        for(BoundVar parameter : parameters)
+            parameter.parent = this;
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void replace(TVar[] vars, Type[] replacements) {
+        for(BoundVar parameter : parameters)
+            parameter.replace(vars, replacements);
+        for(SSAStatement statement = firstStatement;
+                statement != null; statement = statement.next)
+            statement.replace(vars, replacements);
+        exit.replace(vars, replacements);
+    }
+
+    public void collectFreeVariables(SSAFunction function, ArrayList<ValRef> vars) {
+        for(SSAStatement statement = firstStatement;
+                statement != null; statement = statement.next)
+            statement.collectFreeVariables(function, vars);
+        exit.collectFreeVariables(function, vars);
+    }
+
+    @Override
+    public SSAFunction getParentFunction() {
+        return parent;
+    }
+
+    public void lambdaLift(SSALambdaLiftingContext context) {
+        for(SSAStatement statement = firstStatement;
+                statement != null; statement = statement.next)
+            statement.lambdaLift(context);
+    }
+    
+    public SSAStatement getFirstStatement() {
+        return firstStatement;
+    }
+
+    public void setParameter(int position, BoundVar target) {
+        parameters[position] = target;
+        target.parent = this;
+    }
+
+    public void prepare(MethodBuilder mb) {
+        for(SSAStatement stat = firstStatement; stat != null; stat = stat.next)
+            stat.prepare(mb);
+        exit.prepare(mb);
+    }
+
+    public void forValRefs(ValRefVisitor visitor) {
+        for(SSAStatement statement = firstStatement;
+                statement != null; statement = statement.next)
+            statement.forValRefs(visitor);
+        exit.forValRefs(visitor);
+    }
+    
+}