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