X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Finternal%2Fcodegen%2Fssa%2Fstatements%2FLetFunctions.java;h=dc6a8580d713cc8c579ef1cbdfb45aad24dd34ea;hp=ee5dcc7148533bfcaf8a8e44ee7d426b794ce1ca;hb=7e3061cfff1ac4f100fd671feccea25841222cb0;hpb=cb5fc8d606d8b322563e9345c441eecfa7f01753 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 index ee5dcc714..dc6a8580d 100644 --- 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 @@ -1,277 +1,284 @@ -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 vars) { - throw new InternalCompilerError("Should not be called for non-lambda-lifted functions."); - // FIXME inefficient, some kind of caching needed here - /*THashSet tempVars = new THashSet(); - 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 targets = new THashSet(); - ArrayList freeVars = new ArrayList(); - 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 varMap = new THashMap(); - ArrayList oldVarsList = new ArrayList(4); - ArrayList newVarsList = new ArrayList(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 boundVars = new THashSet(); - ArrayList boundVarsList = new ArrayList(4); - ArrayList newFreeVars = new ArrayList(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> varMap = new THashMap>(); - THashMap inVarsMap = new THashMap(); - THashMap oldTargets = new THashMap(); - for(SSAClosure closure = firstClosure; - closure != null; - closure = closure.getNext()) { - THashMap map = new THashMap(outVars.length); - BoundVar[] inVars = new BoundVar[outVars.length]; - for(int i=0;i 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); - } -} +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 vars) { + throw new InternalCompilerError("Should not be called for non-lambda-lifted functions."); + // FIXME inefficient, some kind of caching needed here + /*THashSet tempVars = new THashSet(); + 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 targets = new THashSet(); + ArrayList freeVars = new ArrayList(); + 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 varMap = new THashMap(); + ArrayList oldVarsList = new ArrayList(4); + ArrayList newVarsList = new ArrayList(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()); + newVar.setLabel(var.getLabel()); + 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 boundVars = new THashSet(); + ArrayList boundVarsList = new ArrayList(4); + ArrayList newFreeVars = new ArrayList(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> varMap = new THashMap>(); + THashMap inVarsMap = new THashMap(); + THashMap oldTargets = new THashMap(); + for(SSAClosure closure = firstClosure; + closure != null; + closure = closure.getNext()) { + THashMap map = new THashMap(outVars.length); + BoundVar[] inVars = new BoundVar[outVars.length]; + for(int i=0;i 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); + } + + @Override + public void cleanup() { + for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) + closure.cleanup(); + } +}