]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetFunctions.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / statements / LetFunctions.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetFunctions.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetFunctions.java
new file mode 100644 (file)
index 0000000..7b1db33
--- /dev/null
@@ -0,0 +1,245 @@
+package org.simantics.scl.compiler.internal.codegen.ssa.statements;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
+import org.simantics.scl.compiler.constants.SCLConstant;\r
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;\r
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;\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.FunctionBinder;\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.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.types.TVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+\r
+public class LetFunctions extends SSAStatement implements FunctionBinder {\r
+    long recursiveGroupLocation;\r
+    SSAFunction firstFunction;\r
+\r
+    public LetFunctions() {\r
+    }\r
+    \r
+    public LetFunctions(SSAFunction function) {\r
+        firstFunction = function;\r
+        function.setParent(this);\r
+    }\r
+\r
+    @Override\r
+    public void toString(PrintingContext context) {\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {\r
+            context.indentation();\r
+            context.append(function.getTarget());\r
+            context.append("(" + function.getTarget().occurrenceCount() + ")");\r
+            context.append(" :: ");\r
+            context.append(function.getTarget().getType());\r
+            context.append(" = \n");\r
+            context.indent();\r
+            function.toString(context);\r
+            context.dedent();\r
+        }\r
+    }\r
+    \r
+    public void addFunction(SSAFunction function) {\r
+        function.setParent(this);        \r
+        function.setNext(firstFunction);\r
+        if(firstFunction != null)\r
+            firstFunction.setPrev(function);\r
+        firstFunction = function;\r
+    }\r
+\r
+    @Override\r
+    public void generateCode(MethodBuilder mb) {\r
+        throw new InternalCompilerError("Functions should be lambda lifted before code generation");        \r
+    }\r
+\r
+    @Override\r
+    public void validate(SSAValidationContext context) {\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {\r
+            if(!(function.getTarget() instanceof BoundVar))\r
+                throw new InternalCompilerError();\r
+            function.validate(context);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void destroy() {\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext())\r
+            function.destroy();\r
+    }\r
+\r
+    @Override\r
+    public SSAStatement copy(CopyContext context) {\r
+        LetFunctions result = new LetFunctions();\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {\r
+            SSAFunction newFunction = function.copy(context);\r
+            newFunction.setTarget(context.copy(function.getTarget()));\r
+            result.addFunction(newFunction);\r
+        }\r
+        return result;        \r
+    }\r
+\r
+    @Override\r
+    public void replace(TVar[] vars, Type[] replacements) {\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {\r
+            ((BoundVar)function.getTarget()).replace(vars, replacements);\r
+            function.replace(vars, replacements);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void addBoundVariablesTo(SSAValidationContext context) {\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext())\r
+            context.validBoundVariables.add((BoundVar)function.getTarget());        \r
+    }\r
+\r
+    @Override\r
+    public SSAFunction getFirstFunction() {\r
+        return firstFunction;\r
+    }\r
+\r
+    @Override\r
+    public void setFirstFunction(SSAFunction function) {\r
+        this.firstFunction = function;     \r
+        if(function == null)\r
+            detach();\r
+    }\r
+\r
+    @Override\r
+    public void collectFreeVariables(SSAFunction parentFunction,\r
+            ArrayList<ValRef> vars) {\r
+        throw new InternalCompilerError("Should not be called for non-lambda-lifted functions.");\r
+        // FIXME inefficient, some kind of caching needed here\r
+        /*THashSet<BoundVar> tempVars = new THashSet<BoundVar>();\r
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext())\r
+            function.collectFreeVariables(tempVars);\r
+        \r
+        for(BoundVar var : tempVars)\r
+            if(var.getFunctionParent() != parentFunction)\r
+                vars.add(var);*/\r
+    }\r
+\r
+    @Override\r
+    public void lambdaLift(SSALambdaLiftingContext context) {\r
+        boolean hasValues = false;\r
+        boolean isRecursive = false;\r
+        \r
+        // Lambda lift functions and collect free variables\r
+        THashSet<BoundVar> targets = new THashSet<BoundVar>();\r
+        ArrayList<ValRef> freeVars = new ArrayList<ValRef>();        \r
+        for(SSAFunction function = firstFunction; \r
+                function != null; \r
+                function = function.getNext()) {\r
+            hasValues |= function.getArity() == 0;\r
+            function.lambdaLift(context);\r
+            targets.add((BoundVar)function.getTarget());\r
+            function.collectFreeVariables(freeVars);\r
+        }\r
+                \r
+        // Classify by BoundVars\r
+        THashSet<BoundVar> boundVars = new THashSet<BoundVar>(); \r
+        ArrayList<BoundVar> boundVarsList = new ArrayList<BoundVar>(4);\r
+        ArrayList<ValRef> newFreeVars = new ArrayList<ValRef>(freeVars.size()); \r
+        for(ValRef ref : freeVars) {\r
+            BoundVar var = (BoundVar)ref.getBinding();\r
+            if(targets.contains(var)) {\r
+                isRecursive = true;\r
+                continue;\r
+            }\r
+            if(boundVars.add(var))\r
+                boundVarsList.add(var);\r
+            newFreeVars.add(ref);\r
+            /*BoundVar inVar = map.get(outVar);\r
+            if(inVar == null) {\r
+                inVar = new BoundVar(outVar.getType());\r
+                map.put(outVar, inVar);\r
+                outParameters.add(outVar);\r
+                inParameters.add(inVar);\r
+            }\r
+            ref.replaceBy(inVar);*/\r
+        }\r
+        BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);\r
+        freeVars = newFreeVars;\r
+        \r
+        // Modify functions\r
+        THashMap<SSAFunction, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAFunction, THashMap<BoundVar, BoundVar>>();\r
+        THashMap<SSAFunction, BoundVar[]> inVarsMap = new THashMap<SSAFunction, BoundVar[]>();\r
+        THashMap<SSAFunction, BoundVar> oldTargets = new THashMap<SSAFunction, BoundVar>();\r
+        for(SSAFunction function = firstFunction; \r
+                function != null; \r
+                function = function.getNext()) {\r
+            THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(2*outVars.length);\r
+            BoundVar[] inVars = new BoundVar[outVars.length];            \r
+            for(int i=0;i<inVars.length;++i) {\r
+                inVars[i] = new BoundVar(outVars[i].getType());\r
+                map.put(outVars[i], inVars[i]);\r
+            }\r
+            inVarsMap.put(function, inVars);\r
+            varMap.put(function, map);\r
+            \r
+            function.addParametersInFront(inVars);            \r
+            SCLConstant functionConstant = new SCLConstant(context.createName(), function.getType());\r
+            context.addConstant(functionConstant);   \r
+            oldTargets.put(function, (BoundVar)function.getTarget());\r
+            function.setTarget(functionConstant);\r
+            functionConstant.setDefinition(function);   \r
+            functionConstant.setPrivate(true);\r
+            // TODO handle type parameters\r
+            \r
+            // Define target by an application\r
+            /*new LetApply(oldTarget, functionConstant.createOccurrence(), \r
+                    ValRef.createOccurrences(outVars)).insertBefore(this);*/\r
+        }\r
+        \r
+        for(SSAFunction function = firstFunction; \r
+                function != null; \r
+                function = function.getNext()) {\r
+            BoundVar oldTarget = oldTargets.get(function);\r
+            for(ValRef ref : oldTarget.getOccurences()) {\r
+                SSAFunction parent = ref.getParentFunction();\r
+                BoundVar[] vars = inVarsMap.get(parent);\r
+                if(vars == null)\r
+                    vars = outVars;\r
+                if(vars.length > 0)\r
+                    ref.replaceByApply(function.getTarget(), vars);\r
+                else\r
+                    ref.replaceBy(function.getTarget());\r
+            }\r
+        }\r
+            \r
+        // Fix references\r
+        for(ValRef ref : freeVars) {\r
+            BoundVar inVar = (BoundVar)ref.getBinding();\r
+            if(targets.contains(inVar))\r
+                continue;\r
+            BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);\r
+            ref.replaceBy(outVar);\r
+        }\r
+        \r
+        detach();\r
+        //context.validate();\r
+        \r
+        if(hasValues && isRecursive)\r
+            context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");\r
+    }\r
+    \r
+    @Override\r
+    public void simplify(SSASimplificationContext context) {\r
+        for(SSAFunction function = firstFunction; \r
+                function != null; \r
+                function = function.getNext())\r
+            function.simplify(context);\r
+    }\r
+    \r
+    public void setRecursiveGroupLocation(long recursiveGroupLocation) {\r
+        this.recursiveGroupLocation = recursiveGroupLocation;\r
+    }\r
+}\r