]> gerrit.simantics Code Review - simantics/platform.git/blob
25d9c2544bffd4ab6bb8470ead45408e0900d683
[simantics/platform.git] /
1 package org.simantics.scl.compiler.internal.codegen.ssa.statements;\r
2 \r
3 import java.util.ArrayList;\r
4 \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
20 \r
21 import gnu.trove.map.hash.THashMap;\r
22 import gnu.trove.set.hash.THashSet;\r
23 \r
24 public class LetFunctions extends SSAStatement implements FunctionBinder {\r
25     long recursiveGroupLocation;\r
26     SSAFunction firstFunction;\r
27 \r
28     public LetFunctions() {\r
29     }\r
30     \r
31     public LetFunctions(SSAFunction function) {\r
32         firstFunction = function;\r
33         function.setParent(this);\r
34     }\r
35 \r
36     @Override\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
45             context.indent();\r
46             function.toString(context);\r
47             context.dedent();\r
48         }\r
49     }\r
50     \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
57     }\r
58 \r
59     @Override\r
60     public void generateCode(MethodBuilder mb) {\r
61         throw new InternalCompilerError("Functions should be lambda lifted before code generation");        \r
62     }\r
63 \r
64     @Override\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
70         }\r
71     }\r
72 \r
73     @Override\r
74     public void destroy() {\r
75         for(SSAFunction function = firstFunction; function != null; function = function.getNext())\r
76             function.destroy();\r
77     }\r
78 \r
79     @Override\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
86         }\r
87         return result;        \r
88     }\r
89 \r
90     @Override\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
95         }\r
96     }\r
97 \r
98     @Override\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
102     }\r
103 \r
104     @Override\r
105     public SSAFunction getFirstFunction() {\r
106         return firstFunction;\r
107     }\r
108 \r
109     @Override\r
110     public void setFirstFunction(SSAFunction function) {\r
111         this.firstFunction = function;     \r
112         if(function == null)\r
113             detach();\r
114     }\r
115 \r
116     @Override\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
124         \r
125         for(BoundVar var : tempVars)\r
126             if(var.getFunctionParent() != parentFunction)\r
127                 vars.add(var);*/\r
128     }\r
129 \r
130     @Override\r
131     public void lambdaLift(SSALambdaLiftingContext context) {\r
132         boolean hasValues = false;\r
133         boolean isRecursive = false;\r
134         \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
139                 function != null; \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
145         }\r
146                 \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
155                 continue;\r
156             }\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
166             }\r
167             ref.replaceBy(inVar);*/\r
168         }\r
169         BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);\r
170         freeVars = newFreeVars;\r
171         \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
177                 function != null; \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
184             }\r
185             inVarsMap.put(function, inVars);\r
186             varMap.put(function, map);\r
187             \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
196             \r
197             // Define target by an application\r
198             /*new LetApply(oldTarget, functionConstant.createOccurrence(), \r
199                     ValRef.createOccurrences(outVars)).insertBefore(this);*/\r
200         }\r
201         \r
202         for(SSAFunction function = firstFunction; \r
203                 function != null; \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
209                 if(vars == null)\r
210                     vars = outVars;\r
211                 if(vars.length > 0)\r
212                     ref.replaceByApply(function.getTarget(), vars);\r
213                 else\r
214                     ref.replaceBy(function.getTarget());\r
215             }\r
216         }\r
217             \r
218         // Fix references\r
219         for(ValRef ref : freeVars) {\r
220             BoundVar inVar = (BoundVar)ref.getBinding();\r
221             if(targets.contains(inVar))\r
222                 continue;\r
223             BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);\r
224             ref.replaceBy(outVar);\r
225         }\r
226         \r
227         detach();\r
228         //context.validate();\r
229         \r
230         if(hasValues && isRecursive)\r
231             context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");\r
232     }\r
233     \r
234     @Override\r
235     public void simplify(SSASimplificationContext context) {\r
236         for(SSAFunction function = firstFunction; \r
237                 function != null; \r
238                 function = function.getNext())\r
239             function.simplify(context);\r
240     }\r
241     \r
242     public void setRecursiveGroupLocation(long recursiveGroupLocation) {\r
243         this.recursiveGroupLocation = recursiveGroupLocation;\r
244     }\r
245 }\r