-package org.simantics.scl.compiler.internal.codegen.ssa.statements;\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.references.BoundVar;\r
-import org.simantics.scl.compiler.internal.codegen.references.ValRef;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.SSAClosure;\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.ClosureBinder;\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.internal.codegen.utils.ValRefVisitor;\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
-import gnu.trove.map.hash.THashMap;\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-public class LetFunctions extends SSAStatement implements ClosureBinder {\r
- long recursiveGroupLocation;\r
- SSAClosure firstClosure;\r
-\r
- public LetFunctions() {\r
- }\r
- \r
- public LetFunctions(SSAClosure closure) {\r
- firstClosure = closure;\r
- closure.setParent(this);\r
- }\r
-\r
- @Override\r
- public void toString(PrintingContext context) {\r
- for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
- context.indentation();\r
- context.append(closure.getTarget());\r
- context.append("(" + closure.getTarget().occurrenceCount() + ")");\r
- context.append(" :: ");\r
- context.append(closure.getTarget().getType());\r
- context.append(" = \n");\r
- context.indent();\r
- closure.toString(context);\r
- context.dedent();\r
- }\r
- }\r
- \r
- public void addClosure(SSAClosure closure) {\r
- closure.setParent(this); \r
- closure.setNext(firstClosure);\r
- if(firstClosure != null)\r
- firstClosure.setPrev(closure);\r
- firstClosure = closure;\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(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
- if(!(closure.getTarget() instanceof BoundVar))\r
- throw new InternalCompilerError();\r
- closure.validate(context);\r
- }\r
- }\r
-\r
- @Override\r
- public void destroy() {\r
- for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())\r
- closure.destroy();\r
- }\r
-\r
- @Override\r
- public SSAStatement copy(CopyContext context) {\r
- LetFunctions result = new LetFunctions();\r
- for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
- SSAClosure newFunction = closure.copy(context);\r
- newFunction.setTarget(context.copy(closure.getTarget()));\r
- result.addClosure(newFunction);\r
- }\r
- return result; \r
- }\r
-\r
- @Override\r
- public void replace(TVar[] vars, Type[] replacements) {\r
- for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
- ((BoundVar)closure.getTarget()).replace(vars, replacements);\r
- closure.replace(vars, replacements);\r
- }\r
- }\r
-\r
- @Override\r
- public void addBoundVariablesTo(SSAValidationContext context) {\r
- for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())\r
- context.validBoundVariables.add((BoundVar)closure.getTarget()); \r
- }\r
-\r
- @Override\r
- public SSAClosure getFirstClosure() {\r
- return firstClosure;\r
- }\r
-\r
- @Override\r
- public void setFirstClosure(SSAClosure function) {\r
- this.firstClosure = 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 substructure and collect free variables\r
- THashSet<BoundVar> targets = new THashSet<BoundVar>();\r
- ArrayList<ValRef> freeVars = new ArrayList<ValRef>(); \r
- for(SSAClosure closure = firstClosure; \r
- closure != null; \r
- closure = closure.getNext()) {\r
- hasValues |= closure.isValue();\r
- closure.lambdaLift(context);\r
- targets.add((BoundVar)closure.getTarget());\r
- closure.collectFreeVariables(freeVars);\r
- }\r
- \r
- if(!(firstClosure instanceof SSAFunction) && firstClosure.getNext() == null) {\r
- THashMap<BoundVar, BoundVar> varMap = new THashMap<BoundVar, BoundVar>(); \r
- ArrayList<BoundVar> oldVarsList = new ArrayList<BoundVar>(4);\r
- ArrayList<BoundVar> newVarsList = new ArrayList<BoundVar>(4);\r
- BoundVar newTarget = null;\r
- for(ValRef ref : freeVars) {\r
- BoundVar var = (BoundVar)ref.getBinding();\r
- if(targets.contains(var)) {\r
- if(newTarget == null)\r
- newTarget = new BoundVar(var.getType());\r
- ref.replaceBy(newTarget);\r
- continue;\r
- }\r
- BoundVar newVar = varMap.get(var);\r
- if(newVar == null) {\r
- newVar = new BoundVar(var.getType());\r
- oldVarsList.add(var);\r
- newVarsList.add(newVar);\r
- varMap.put(var, newVar);\r
- }\r
- ref.replaceBy(newVar);\r
- }\r
- Constant constant = firstClosure.liftClosure(newTarget, newVarsList.toArray(new BoundVar[newVarsList.size()]));\r
- new LetApply(targets.iterator().next(), Types.PROC, constant.createOccurrence(), ValRef.createOccurrences(oldVarsList))\r
- .insertBefore(this);\r
- detach();\r
- context.addClosure(firstClosure);\r
- return;\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
- }\r
- BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);\r
- freeVars = newFreeVars;\r
- \r
- // Modify functions\r
- THashMap<SSAClosure, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAClosure, THashMap<BoundVar, BoundVar>>();\r
- THashMap<SSAClosure, BoundVar[]> inVarsMap = new THashMap<SSAClosure, BoundVar[]>();\r
- THashMap<SSAClosure, BoundVar> oldTargets = new THashMap<SSAClosure, BoundVar>();\r
- for(SSAClosure closure = firstClosure; \r
- closure != null; \r
- closure = closure.getNext()) {\r
- THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(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(closure, inVars);\r
- varMap.put(closure, map);\r
- \r
- closure.parametrize(inVars); \r
- SCLConstant functionConstant = new SCLConstant(context.createName(), closure.getType());\r
- context.addConstant(functionConstant); \r
- oldTargets.put(closure, (BoundVar)closure.getTarget());\r
- closure.setTarget(functionConstant);\r
- functionConstant.setDefinition((SSAFunction)closure); \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(SSAClosure closure = firstClosure; \r
- closure != null; \r
- closure = closure.getNext()) {\r
- BoundVar oldTarget = oldTargets.get(closure);\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(closure.getTarget(), vars);\r
- else\r
- ref.replaceBy(closure.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(SSAClosure function = firstClosure; \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
- @Override\r
- public void forValRefs(ValRefVisitor visitor) {\r
- for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())\r
- closure.forValRefs(visitor); \r
- }\r
-}\r
+package org.simantics.scl.compiler.internal.codegen.ssa.statements;
+
+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.SCLConstant;
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAClosure;
+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.ClosureBinder;
+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.SSALambdaLiftingContext;
+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.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
+public class LetFunctions extends SSAStatement implements ClosureBinder {
+ long recursiveGroupLocation;
+ SSAClosure firstClosure;
+
+ public LetFunctions() {
+ }
+
+ public LetFunctions(SSAClosure closure) {
+ firstClosure = closure;
+ closure.setParent(this);
+ }
+
+ @Override
+ public void toString(PrintingContext context) {
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+ context.indentation();
+ context.append(closure.getTarget());
+ context.append("(" + closure.getTarget().occurrenceCount() + ")");
+ context.append(" :: ");
+ context.append(closure.getTarget().getType());
+ context.append(" = \n");
+ context.indent();
+ closure.toString(context);
+ context.dedent();
+ }
+ }
+
+ public void addClosure(SSAClosure closure) {
+ closure.setParent(this);
+ closure.setNext(firstClosure);
+ if(firstClosure != null)
+ firstClosure.setPrev(closure);
+ firstClosure = closure;
+ }
+
+ @Override
+ public void generateCode(MethodBuilder mb) {
+ throw new InternalCompilerError("Functions should be lambda lifted before code generation");
+ }
+
+ @Override
+ public void validate(SSAValidationContext context) {
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+ if(!(closure.getTarget() instanceof BoundVar))
+ throw new InternalCompilerError();
+ closure.validate(context);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+ closure.destroy();
+ }
+
+ @Override
+ public SSAStatement copy(CopyContext context) {
+ LetFunctions result = new LetFunctions();
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+ SSAClosure newFunction = closure.copy(context);
+ newFunction.setTarget(context.copy(closure.getTarget()));
+ result.addClosure(newFunction);
+ }
+ return result;
+ }
+
+ @Override
+ public void replace(TVar[] vars, Type[] replacements) {
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+ ((BoundVar)closure.getTarget()).replace(vars, replacements);
+ closure.replace(vars, replacements);
+ }
+ }
+
+ @Override
+ public void addBoundVariablesTo(SSAValidationContext context) {
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+ context.validBoundVariables.add((BoundVar)closure.getTarget());
+ }
+
+ @Override
+ public SSAClosure getFirstClosure() {
+ return firstClosure;
+ }
+
+ @Override
+ public void setFirstClosure(SSAClosure function) {
+ this.firstClosure = function;
+ if(function == null)
+ detach();
+ }
+
+ @Override
+ public void collectFreeVariables(SSAFunction parentFunction,
+ ArrayList<ValRef> vars) {
+ throw new InternalCompilerError("Should not be called for non-lambda-lifted functions.");
+ // FIXME inefficient, some kind of caching needed here
+ /*THashSet<BoundVar> tempVars = new THashSet<BoundVar>();
+ for(SSAFunction function = firstFunction; function != null; function = function.getNext())
+ function.collectFreeVariables(tempVars);
+
+ for(BoundVar var : tempVars)
+ if(var.getFunctionParent() != parentFunction)
+ vars.add(var);*/
+ }
+
+ @Override
+ public void lambdaLift(SSALambdaLiftingContext context) {
+ boolean hasValues = false;
+ boolean isRecursive = false;
+
+ // Lambda lift substructure and collect free variables
+ THashSet<BoundVar> targets = new THashSet<BoundVar>();
+ ArrayList<ValRef> freeVars = new ArrayList<ValRef>();
+ for(SSAClosure closure = firstClosure;
+ closure != null;
+ closure = closure.getNext()) {
+ hasValues |= closure.isValue();
+ closure.lambdaLift(context);
+ targets.add((BoundVar)closure.getTarget());
+ closure.collectFreeVariables(freeVars);
+ }
+
+ if(!(firstClosure instanceof SSAFunction) && firstClosure.getNext() == null) {
+ THashMap<BoundVar, BoundVar> varMap = new THashMap<BoundVar, BoundVar>();
+ ArrayList<BoundVar> oldVarsList = new ArrayList<BoundVar>(4);
+ ArrayList<BoundVar> newVarsList = new ArrayList<BoundVar>(4);
+ BoundVar newTarget = null;
+ for(ValRef ref : freeVars) {
+ BoundVar var = (BoundVar)ref.getBinding();
+ if(targets.contains(var)) {
+ if(newTarget == null)
+ newTarget = new BoundVar(var.getType());
+ ref.replaceBy(newTarget);
+ continue;
+ }
+ BoundVar newVar = varMap.get(var);
+ if(newVar == null) {
+ newVar = new BoundVar(var.getType());
+ oldVarsList.add(var);
+ newVarsList.add(newVar);
+ varMap.put(var, newVar);
+ }
+ ref.replaceBy(newVar);
+ }
+ Constant constant = firstClosure.liftClosure(newTarget, newVarsList.toArray(new BoundVar[newVarsList.size()]));
+ new LetApply(targets.iterator().next(), Types.PROC, constant.createOccurrence(), ValRef.createOccurrences(oldVarsList))
+ .insertBefore(this);
+ detach();
+ context.addClosure(firstClosure);
+ return;
+ }
+
+ // Classify by BoundVars
+ THashSet<BoundVar> boundVars = new THashSet<BoundVar>();
+ ArrayList<BoundVar> boundVarsList = new ArrayList<BoundVar>(4);
+ ArrayList<ValRef> newFreeVars = new ArrayList<ValRef>(freeVars.size());
+ for(ValRef ref : freeVars) {
+ BoundVar var = (BoundVar)ref.getBinding();
+ if(targets.contains(var)) {
+ isRecursive = true;
+ continue;
+ }
+ if(boundVars.add(var))
+ boundVarsList.add(var);
+ newFreeVars.add(ref);
+ }
+ BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);
+ freeVars = newFreeVars;
+
+ // Modify functions
+ THashMap<SSAClosure, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAClosure, THashMap<BoundVar, BoundVar>>();
+ THashMap<SSAClosure, BoundVar[]> inVarsMap = new THashMap<SSAClosure, BoundVar[]>();
+ THashMap<SSAClosure, BoundVar> oldTargets = new THashMap<SSAClosure, BoundVar>();
+ for(SSAClosure closure = firstClosure;
+ closure != null;
+ closure = closure.getNext()) {
+ THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(outVars.length);
+ BoundVar[] inVars = new BoundVar[outVars.length];
+ for(int i=0;i<inVars.length;++i) {
+ inVars[i] = new BoundVar(outVars[i].getType());
+ map.put(outVars[i], inVars[i]);
+ }
+ inVarsMap.put(closure, inVars);
+ varMap.put(closure, map);
+
+ closure.parametrize(inVars);
+ SCLConstant functionConstant = new SCLConstant(context.createName(), closure.getType());
+ context.addConstant(functionConstant);
+ oldTargets.put(closure, (BoundVar)closure.getTarget());
+ closure.setTarget(functionConstant);
+ functionConstant.setDefinition((SSAFunction)closure);
+ functionConstant.setPrivate(true);
+ // TODO handle type parameters
+
+ // Define target by an application
+ /*new LetApply(oldTarget, functionConstant.createOccurrence(),
+ ValRef.createOccurrences(outVars)).insertBefore(this);*/
+ }
+
+ for(SSAClosure closure = firstClosure;
+ closure != null;
+ closure = closure.getNext()) {
+ BoundVar oldTarget = oldTargets.get(closure);
+ for(ValRef ref : oldTarget.getOccurences()) {
+ SSAFunction parent = ref.getParentFunction();
+ BoundVar[] vars = inVarsMap.get(parent);
+ if(vars == null)
+ vars = outVars;
+ if(vars.length > 0)
+ ref.replaceByApply(closure.getTarget(), vars);
+ else
+ ref.replaceBy(closure.getTarget());
+ }
+ }
+
+ // Fix references
+ for(ValRef ref : freeVars) {
+ BoundVar inVar = (BoundVar)ref.getBinding();
+ if(targets.contains(inVar))
+ continue;
+ BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);
+ ref.replaceBy(outVar);
+ }
+
+ detach();
+ //context.validate();
+
+ if(hasValues && isRecursive)
+ context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");
+ }
+
+ @Override
+ public void simplify(SSASimplificationContext context) {
+ for(SSAClosure function = firstClosure;
+ function != null;
+ function = function.getNext())
+ function.simplify(context);
+ }
+
+ public void setRecursiveGroupLocation(long recursiveGroupLocation) {
+ this.recursiveGroupLocation = recursiveGroupLocation;
+ }
+
+ @Override
+ public void forValRefs(ValRefVisitor visitor) {
+ for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+ closure.forValRefs(visitor);
+ }
+}