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.SCLConstant;
\r
7 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
\r
8 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
\r
9 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
\r
10 import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;
\r
11 import org.simantics.scl.compiler.internal.codegen.ssa.binders.FunctionBinder;
\r
12 import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
\r
13 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
\r
14 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
\r
15 import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
\r
16 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
\r
17 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
\r
18 import org.simantics.scl.compiler.types.TVar;
\r
19 import org.simantics.scl.compiler.types.Type;
\r
21 import gnu.trove.map.hash.THashMap;
\r
22 import gnu.trove.set.hash.THashSet;
\r
24 public class LetFunctions extends SSAStatement implements FunctionBinder {
\r
25 long recursiveGroupLocation;
\r
26 SSAFunction firstFunction;
\r
28 public LetFunctions() {
\r
31 public LetFunctions(SSAFunction function) {
\r
32 firstFunction = function;
\r
33 function.setParent(this);
\r
37 public void toString(PrintingContext context) {
\r
38 for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {
\r
39 context.indentation();
\r
40 context.append(function.getTarget());
\r
41 context.append("(" + function.getTarget().occurrenceCount() + ")");
\r
42 context.append(" :: ");
\r
43 context.append(function.getTarget().getType());
\r
44 context.append(" = \n");
\r
46 function.toString(context);
\r
51 public void addFunction(SSAFunction function) {
\r
52 function.setParent(this);
\r
53 function.setNext(firstFunction);
\r
54 if(firstFunction != null)
\r
55 firstFunction.setPrev(function);
\r
56 firstFunction = function;
\r
60 public void generateCode(MethodBuilder mb) {
\r
61 throw new InternalCompilerError("Functions should be lambda lifted before code generation");
\r
65 public void validate(SSAValidationContext context) {
\r
66 for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {
\r
67 if(!(function.getTarget() instanceof BoundVar))
\r
68 throw new InternalCompilerError();
\r
69 function.validate(context);
\r
74 public void destroy() {
\r
75 for(SSAFunction function = firstFunction; function != null; function = function.getNext())
\r
80 public SSAStatement copy(CopyContext context) {
\r
81 LetFunctions result = new LetFunctions();
\r
82 for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {
\r
83 SSAFunction newFunction = function.copy(context);
\r
84 newFunction.setTarget(context.copy(function.getTarget()));
\r
85 result.addFunction(newFunction);
\r
91 public void replace(TVar[] vars, Type[] replacements) {
\r
92 for(SSAFunction function = firstFunction; function != null; function = function.getNext()) {
\r
93 ((BoundVar)function.getTarget()).replace(vars, replacements);
\r
94 function.replace(vars, replacements);
\r
99 public void addBoundVariablesTo(SSAValidationContext context) {
\r
100 for(SSAFunction function = firstFunction; function != null; function = function.getNext())
\r
101 context.validBoundVariables.add((BoundVar)function.getTarget());
\r
105 public SSAFunction getFirstFunction() {
\r
106 return firstFunction;
\r
110 public void setFirstFunction(SSAFunction function) {
\r
111 this.firstFunction = function;
\r
112 if(function == null)
\r
117 public void collectFreeVariables(SSAFunction parentFunction,
\r
118 ArrayList<ValRef> vars) {
\r
119 throw new InternalCompilerError("Should not be called for non-lambda-lifted functions.");
\r
120 // FIXME inefficient, some kind of caching needed here
\r
121 /*THashSet<BoundVar> tempVars = new THashSet<BoundVar>();
\r
122 for(SSAFunction function = firstFunction; function != null; function = function.getNext())
\r
123 function.collectFreeVariables(tempVars);
\r
125 for(BoundVar var : tempVars)
\r
126 if(var.getFunctionParent() != parentFunction)
\r
131 public void lambdaLift(SSALambdaLiftingContext context) {
\r
132 boolean hasValues = false;
\r
133 boolean isRecursive = false;
\r
135 // Lambda lift functions and collect free variables
\r
136 THashSet<BoundVar> targets = new THashSet<BoundVar>();
\r
137 ArrayList<ValRef> freeVars = new ArrayList<ValRef>();
\r
138 for(SSAFunction function = firstFunction;
\r
140 function = function.getNext()) {
\r
141 hasValues |= function.getArity() == 0;
\r
142 function.lambdaLift(context);
\r
143 targets.add((BoundVar)function.getTarget());
\r
144 function.collectFreeVariables(freeVars);
\r
147 // Classify by BoundVars
\r
148 THashSet<BoundVar> boundVars = new THashSet<BoundVar>();
\r
149 ArrayList<BoundVar> boundVarsList = new ArrayList<BoundVar>(4);
\r
150 ArrayList<ValRef> newFreeVars = new ArrayList<ValRef>(freeVars.size());
\r
151 for(ValRef ref : freeVars) {
\r
152 BoundVar var = (BoundVar)ref.getBinding();
\r
153 if(targets.contains(var)) {
\r
154 isRecursive = true;
\r
157 if(boundVars.add(var))
\r
158 boundVarsList.add(var);
\r
159 newFreeVars.add(ref);
\r
160 /*BoundVar inVar = map.get(outVar);
\r
161 if(inVar == null) {
\r
162 inVar = new BoundVar(outVar.getType());
\r
163 map.put(outVar, inVar);
\r
164 outParameters.add(outVar);
\r
165 inParameters.add(inVar);
\r
167 ref.replaceBy(inVar);*/
\r
169 BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);
\r
170 freeVars = newFreeVars;
\r
172 // Modify functions
\r
173 THashMap<SSAFunction, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAFunction, THashMap<BoundVar, BoundVar>>();
\r
174 THashMap<SSAFunction, BoundVar[]> inVarsMap = new THashMap<SSAFunction, BoundVar[]>();
\r
175 THashMap<SSAFunction, BoundVar> oldTargets = new THashMap<SSAFunction, BoundVar>();
\r
176 for(SSAFunction function = firstFunction;
\r
178 function = function.getNext()) {
\r
179 THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(2*outVars.length);
\r
180 BoundVar[] inVars = new BoundVar[outVars.length];
\r
181 for(int i=0;i<inVars.length;++i) {
\r
182 inVars[i] = new BoundVar(outVars[i].getType());
\r
183 map.put(outVars[i], inVars[i]);
\r
185 inVarsMap.put(function, inVars);
\r
186 varMap.put(function, map);
\r
188 function.addParametersInFront(inVars);
\r
189 SCLConstant functionConstant = new SCLConstant(context.createName(), function.getType());
\r
190 context.addConstant(functionConstant);
\r
191 oldTargets.put(function, (BoundVar)function.getTarget());
\r
192 function.setTarget(functionConstant);
\r
193 functionConstant.setDefinition(function);
\r
194 functionConstant.setPrivate(true);
\r
195 // TODO handle type parameters
\r
197 // Define target by an application
\r
198 /*new LetApply(oldTarget, functionConstant.createOccurrence(),
\r
199 ValRef.createOccurrences(outVars)).insertBefore(this);*/
\r
202 for(SSAFunction function = firstFunction;
\r
204 function = function.getNext()) {
\r
205 BoundVar oldTarget = oldTargets.get(function);
\r
206 for(ValRef ref : oldTarget.getOccurences()) {
\r
207 SSAFunction parent = ref.getParentFunction();
\r
208 BoundVar[] vars = inVarsMap.get(parent);
\r
211 if(vars.length > 0)
\r
212 ref.replaceByApply(function.getTarget(), vars);
\r
214 ref.replaceBy(function.getTarget());
\r
219 for(ValRef ref : freeVars) {
\r
220 BoundVar inVar = (BoundVar)ref.getBinding();
\r
221 if(targets.contains(inVar))
\r
223 BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);
\r
224 ref.replaceBy(outVar);
\r
228 //context.validate();
\r
230 if(hasValues && isRecursive)
\r
231 context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");
\r
235 public void simplify(SSASimplificationContext context) {
\r
236 for(SSAFunction function = firstFunction;
\r
238 function = function.getNext())
\r
239 function.simplify(context);
\r
242 public void setRecursiveGroupLocation(long recursiveGroupLocation) {
\r
243 this.recursiveGroupLocation = recursiveGroupLocation;
\r