1 package org.simantics.scl.compiler.internal.codegen.ssa.statements;
\r
3 import java.util.ArrayList;
\r
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
\r
6 import org.simantics.scl.compiler.constants.Constant;
\r
7 import org.simantics.scl.compiler.constants.SCLConstant;
\r
8 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
\r
9 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
\r
10 import org.simantics.scl.compiler.internal.codegen.ssa.SSAClosure;
\r
11 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
\r
12 import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;
\r
13 import org.simantics.scl.compiler.internal.codegen.ssa.binders.ClosureBinder;
\r
14 import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
\r
15 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
\r
16 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
\r
17 import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
\r
18 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
\r
19 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
\r
20 import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
\r
21 import org.simantics.scl.compiler.types.TVar;
\r
22 import org.simantics.scl.compiler.types.Type;
\r
23 import org.simantics.scl.compiler.types.Types;
\r
25 import gnu.trove.map.hash.THashMap;
\r
26 import gnu.trove.set.hash.THashSet;
\r
28 public class LetFunctions extends SSAStatement implements ClosureBinder {
\r
29 long recursiveGroupLocation;
\r
30 SSAClosure firstClosure;
\r
32 public LetFunctions() {
\r
35 public LetFunctions(SSAClosure closure) {
\r
36 firstClosure = closure;
\r
37 closure.setParent(this);
\r
41 public void toString(PrintingContext context) {
\r
42 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
\r
43 context.indentation();
\r
44 context.append(closure.getTarget());
\r
45 context.append("(" + closure.getTarget().occurrenceCount() + ")");
\r
46 context.append(" :: ");
\r
47 context.append(closure.getTarget().getType());
\r
48 context.append(" = \n");
\r
50 closure.toString(context);
\r
55 public void addClosure(SSAClosure closure) {
\r
56 closure.setParent(this);
\r
57 closure.setNext(firstClosure);
\r
58 if(firstClosure != null)
\r
59 firstClosure.setPrev(closure);
\r
60 firstClosure = closure;
\r
64 public void generateCode(MethodBuilder mb) {
\r
65 throw new InternalCompilerError("Functions should be lambda lifted before code generation");
\r
69 public void validate(SSAValidationContext context) {
\r
70 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
\r
71 if(!(closure.getTarget() instanceof BoundVar))
\r
72 throw new InternalCompilerError();
\r
73 closure.validate(context);
\r
78 public void destroy() {
\r
79 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
\r
84 public SSAStatement copy(CopyContext context) {
\r
85 LetFunctions result = new LetFunctions();
\r
86 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
\r
87 SSAClosure newFunction = closure.copy(context);
\r
88 newFunction.setTarget(context.copy(closure.getTarget()));
\r
89 result.addClosure(newFunction);
\r
95 public void replace(TVar[] vars, Type[] replacements) {
\r
96 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
\r
97 ((BoundVar)closure.getTarget()).replace(vars, replacements);
\r
98 closure.replace(vars, replacements);
\r
103 public void addBoundVariablesTo(SSAValidationContext context) {
\r
104 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
\r
105 context.validBoundVariables.add((BoundVar)closure.getTarget());
\r
109 public SSAClosure getFirstClosure() {
\r
110 return firstClosure;
\r
114 public void setFirstClosure(SSAClosure function) {
\r
115 this.firstClosure = function;
\r
116 if(function == null)
\r
121 public void collectFreeVariables(SSAFunction parentFunction,
\r
122 ArrayList<ValRef> vars) {
\r
123 throw new InternalCompilerError("Should not be called for non-lambda-lifted functions.");
\r
124 // FIXME inefficient, some kind of caching needed here
\r
125 /*THashSet<BoundVar> tempVars = new THashSet<BoundVar>();
\r
126 for(SSAFunction function = firstFunction; function != null; function = function.getNext())
\r
127 function.collectFreeVariables(tempVars);
\r
129 for(BoundVar var : tempVars)
\r
130 if(var.getFunctionParent() != parentFunction)
\r
135 public void lambdaLift(SSALambdaLiftingContext context) {
\r
136 boolean hasValues = false;
\r
137 boolean isRecursive = false;
\r
139 // Lambda lift substructure and collect free variables
\r
140 THashSet<BoundVar> targets = new THashSet<BoundVar>();
\r
141 ArrayList<ValRef> freeVars = new ArrayList<ValRef>();
\r
142 for(SSAClosure closure = firstClosure;
\r
144 closure = closure.getNext()) {
\r
145 hasValues |= closure.isValue();
\r
146 closure.lambdaLift(context);
\r
147 targets.add((BoundVar)closure.getTarget());
\r
148 closure.collectFreeVariables(freeVars);
\r
151 if(!(firstClosure instanceof SSAFunction) && firstClosure.getNext() == null) {
\r
152 THashMap<BoundVar, BoundVar> varMap = new THashMap<BoundVar, BoundVar>();
\r
153 ArrayList<BoundVar> oldVarsList = new ArrayList<BoundVar>(4);
\r
154 ArrayList<BoundVar> newVarsList = new ArrayList<BoundVar>(4);
\r
155 BoundVar newTarget = null;
\r
156 for(ValRef ref : freeVars) {
\r
157 BoundVar var = (BoundVar)ref.getBinding();
\r
158 if(targets.contains(var)) {
\r
159 if(newTarget == null)
\r
160 newTarget = new BoundVar(var.getType());
\r
161 ref.replaceBy(newTarget);
\r
164 BoundVar newVar = varMap.get(var);
\r
165 if(newVar == null) {
\r
166 newVar = new BoundVar(var.getType());
\r
167 oldVarsList.add(var);
\r
168 newVarsList.add(newVar);
\r
169 varMap.put(var, newVar);
\r
171 ref.replaceBy(newVar);
\r
173 Constant constant = firstClosure.liftClosure(newTarget, newVarsList.toArray(new BoundVar[newVarsList.size()]));
\r
174 new LetApply(targets.iterator().next(), Types.PROC, constant.createOccurrence(), ValRef.createOccurrences(oldVarsList))
\r
175 .insertBefore(this);
\r
177 context.addClosure(firstClosure);
\r
181 // Classify by BoundVars
\r
182 THashSet<BoundVar> boundVars = new THashSet<BoundVar>();
\r
183 ArrayList<BoundVar> boundVarsList = new ArrayList<BoundVar>(4);
\r
184 ArrayList<ValRef> newFreeVars = new ArrayList<ValRef>(freeVars.size());
\r
185 for(ValRef ref : freeVars) {
\r
186 BoundVar var = (BoundVar)ref.getBinding();
\r
187 if(targets.contains(var)) {
\r
188 isRecursive = true;
\r
191 if(boundVars.add(var))
\r
192 boundVarsList.add(var);
\r
193 newFreeVars.add(ref);
\r
195 BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);
\r
196 freeVars = newFreeVars;
\r
198 // Modify functions
\r
199 THashMap<SSAClosure, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAClosure, THashMap<BoundVar, BoundVar>>();
\r
200 THashMap<SSAClosure, BoundVar[]> inVarsMap = new THashMap<SSAClosure, BoundVar[]>();
\r
201 THashMap<SSAClosure, BoundVar> oldTargets = new THashMap<SSAClosure, BoundVar>();
\r
202 for(SSAClosure closure = firstClosure;
\r
204 closure = closure.getNext()) {
\r
205 THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(outVars.length);
\r
206 BoundVar[] inVars = new BoundVar[outVars.length];
\r
207 for(int i=0;i<inVars.length;++i) {
\r
208 inVars[i] = new BoundVar(outVars[i].getType());
\r
209 map.put(outVars[i], inVars[i]);
\r
211 inVarsMap.put(closure, inVars);
\r
212 varMap.put(closure, map);
\r
214 closure.parametrize(inVars);
\r
215 SCLConstant functionConstant = new SCLConstant(context.createName(), closure.getType());
\r
216 context.addConstant(functionConstant);
\r
217 oldTargets.put(closure, (BoundVar)closure.getTarget());
\r
218 closure.setTarget(functionConstant);
\r
219 functionConstant.setDefinition((SSAFunction)closure);
\r
220 functionConstant.setPrivate(true);
\r
221 // TODO handle type parameters
\r
223 // Define target by an application
\r
224 /*new LetApply(oldTarget, functionConstant.createOccurrence(),
\r
225 ValRef.createOccurrences(outVars)).insertBefore(this);*/
\r
228 for(SSAClosure closure = firstClosure;
\r
230 closure = closure.getNext()) {
\r
231 BoundVar oldTarget = oldTargets.get(closure);
\r
232 for(ValRef ref : oldTarget.getOccurences()) {
\r
233 SSAFunction parent = ref.getParentFunction();
\r
234 BoundVar[] vars = inVarsMap.get(parent);
\r
237 if(vars.length > 0)
\r
238 ref.replaceByApply(closure.getTarget(), vars);
\r
240 ref.replaceBy(closure.getTarget());
\r
245 for(ValRef ref : freeVars) {
\r
246 BoundVar inVar = (BoundVar)ref.getBinding();
\r
247 if(targets.contains(inVar))
\r
249 BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);
\r
250 ref.replaceBy(outVar);
\r
254 //context.validate();
\r
256 if(hasValues && isRecursive)
\r
257 context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");
\r
261 public void simplify(SSASimplificationContext context) {
\r
262 for(SSAClosure function = firstClosure;
\r
264 function = function.getNext())
\r
265 function.simplify(context);
\r
268 public void setRecursiveGroupLocation(long recursiveGroupLocation) {
\r
269 this.recursiveGroupLocation = recursiveGroupLocation;
\r
273 public void forValRefs(ValRefVisitor visitor) {
\r
274 for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
\r
275 closure.forValRefs(visitor);
\r