1 package org.simantics.scl.compiler.constants;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Arrays;
\r
6 import org.simantics.scl.compiler.common.names.Name;
\r
7 import org.simantics.scl.compiler.common.names.Named;
\r
8 import org.simantics.scl.compiler.internal.codegen.optimization.Optimization;
\r
9 import org.simantics.scl.compiler.internal.codegen.optimization.OptimizationMap;
\r
10 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
\r
11 import org.simantics.scl.compiler.internal.codegen.references.Val;
\r
12 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
\r
13 import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
\r
14 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
\r
15 import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;
\r
16 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
\r
17 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions;
\r
18 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
\r
19 import org.simantics.scl.compiler.types.TVar;
\r
20 import org.simantics.scl.compiler.types.Type;
\r
21 import org.simantics.scl.compiler.types.Types;
\r
23 public class SCLConstant extends DelegateConstant implements Named {
\r
25 public Name name; // Needed only for debugging
\r
26 public SSAFunction definition;
\r
27 public SSAFunction inlinableDefinition;
\r
28 public int inlineArity = Integer.MAX_VALUE;
\r
29 public int inlinePhaseMask = 0xffffffff;
\r
30 public boolean isPrivate = false;
\r
32 public SCLConstant(Name name, Type type) {
\r
37 public void setInlineArity(int inlineArity, int inlinePhaseMask) {
\r
38 this.inlineArity = inlineArity;
\r
39 this.inlinePhaseMask = inlinePhaseMask;
\r
40 //System.out.println(name + " " + inlineArity + " " + inlinePhaseMask);
\r
43 public void setPrivate(boolean isPrivate) {
\r
44 this.isPrivate = isPrivate;
\r
47 public void setDefinition(SSAFunction definition) {
\r
48 this.definition = definition;
\r
51 public SSAFunction getDefinition() {
\r
56 public void inline(SSASimplificationContext context, LetApply apply) {
\r
57 if(inlineTailCallToSelf(context, apply)) {
\r
60 /*if(tryBetaReduce(context, apply)) {
\r
63 if(basicInline(context, apply)) {
\r
66 trySpecialize(context, apply);
\r
68 Optimization opt = OptimizationMap.OPTIMIZATIONS.get(name);
\r
70 opt.inline(context, apply);
\r
73 static int inlineCount = 0;
\r
75 private boolean canInlineInPhase(int phase) {
\r
76 return ((inlinePhaseMask >> phase)&1) == 1;
\r
79 private boolean basicInline(SSASimplificationContext context, LetApply apply) {
\r
80 if(!canInlineInPhase(context.getPhase())) {
\r
81 //System.out.println("Cannot optimize " + name + " in phase " + context.getPhase());
\r
84 ValRef functionRef = apply.getFunction();
\r
85 ValRef[] parameters = apply.getParameters();
\r
86 SSAFunction def = inlinableDefinition == null ? definition : inlinableDefinition;
\r
87 if(parameters.length < inlineArity &&
\r
89 || parameters.length != def.getArity()
\r
90 || hasMoreThanOneOccurences()))
\r
93 //if(def.getArity() == 0)
\r
94 // return false; // FIXME
\r
96 //System.out.println("basicInline: " + apply);
\r
97 //System.out.println("def: " + def);
\r
99 if(isPrivate && !hasMoreThanOneOccurences())
\r
100 context.removeConstant(name);
\r
104 if(parameters.length >= def.getArity()) {
\r
105 if(parameters.length != def.getArity())
\r
106 apply.split(def.getArity());
\r
108 context.markModified("SCLConstant.beta-constant " + getName());
\r
110 else /*if(parameters.length < def.getArity())*/ {
\r
111 def.applyTypes(functionRef.getTypeParameters());
\r
112 def.apply(parameters);
\r
114 def.setTarget(apply.getTarget());
\r
115 new LetFunctions(def).insertBefore(apply);
\r
118 context.markModified("SCLConstant.partial-beta-constant " + getName());
\r
121 /*Name newName = Name.create(name.module,
\r
122 name.name + "_S" + (++inlineCount));
\r
123 SCLConstant newConstant = new SCLConstant(newName, type);
\r
124 newConstant.setPrivate(true);
\r
125 newConstant.setDefinition(definition.copy()); */
\r
126 /*System.out.println("*** 1 *************************************");
\r
127 System.out.println(definition);
\r
128 System.out.println("*** 2 *************************************");
\r
129 System.out.println(newConstant.definition);
\r
132 apply.setFunction(newConstant.createOccurrence(function.getTypeParameters()));
\r
134 context.addConstant(newConstant);
\r
136 context.markModified();
\r
138 newConstant.trySpecialize(context, apply);
\r
144 private boolean inlineTailCallToSelf(SSASimplificationContext context, LetApply apply) {
\r
145 SSAFunction thisFunction = apply.getParent().getParent();
\r
146 if(thisFunction != definition)
\r
148 ValRef ref = apply.getTarget().getOccurrence();
\r
149 if(ref == null || ref.getNext() != null)
\r
151 if(!(ref.getParent() instanceof Jump))
\r
153 Jump jump = (Jump)ref.getParent();
\r
154 if(jump.getParameters().length != 1)
\r
156 if(jump.getTarget().getBinding() != thisFunction.getReturnCont())
\r
158 if(apply.getParameters().length != thisFunction.getArity())
\r
161 jump.getTarget().remove();
\r
162 jump.setTarget(thisFunction.getFirstBlock().createOccurrence());
\r
163 jump.setParameters(apply.getParameters());
\r
165 apply.getFunction().remove();
\r
168 context.markModified("SCLConstant.simplify-tail-call");
\r
173 private void trySpecialize(SSASimplificationContext context, LetApply apply) {
\r
176 if(hasMoreThanOneOccurences())
\r
178 if(apply.getParent().getParent() == definition)
\r
181 // Specialization of type parameters
\r
183 ValRef functionRef = apply.getFunction();
\r
184 Type[] pValues = functionRef.getTypeParameters();
\r
185 boolean hasComplexTypes = false;
\r
186 for(Type type : pValues)
\r
187 if(!(Types.canonical(type) instanceof TVar)) {
\r
188 hasComplexTypes = true;
\r
191 if(hasComplexTypes) {
\r
192 /*PrintingContext pc = new PrintingContext();
\r
193 pc.append(">> BEFORE >>\n");
\r
194 definition.toString(pc);*/
\r
196 TVar[] pVars = definition.getTypeParameters();
\r
198 if(pVars.length == pValues.length)
\r
199 pVarsTail = TVar.EMPTY_ARRAY;
\r
201 pVarsTail = Arrays.copyOfRange(pVars, pValues.length, pVars.length);
\r
202 pVars = Arrays.copyOf(pVars, pValues.length);
\r
204 type = Types.instantiate(type, pValues);
\r
205 /*pc.append("REPLACE: ");
\r
208 pc.append(pValues);
\r
210 definition.replace(pVars, pValues);
\r
211 TVar[] newParameters = Types.freeVarsArray(pValues);
\r
212 type = Types.forAll(newParameters, type);
\r
213 functionRef.setTypeParameters(newParameters);
\r
214 definition.setTypeParameters(Types.concat(newParameters, pVarsTail));
\r
216 /*pc.append(">> AFTER >>\n");
\r
217 definition.toString(pc);
\r
218 System.out.println(pc);*/
\r
219 context.markModified("SCLConstant.specialize-types");
\r
223 if(!definition.getFirstBlock().hasNoOccurences())
\r
224 // TODO We can flex this requirement if all jumps to the first block
\r
225 // give same values to the first block
\r
228 // Specialization of parameters
\r
229 ValRef[] parameters = apply.getParameters();
\r
230 ValRef[] specialization = null;
\r
231 int arity = Math.min(parameters.length, definition.getArity());
\r
232 for(int i=0;i<arity;++i) {
\r
233 Val val = parameters[i].getBinding();
\r
234 if(val instanceof Constant) {
\r
235 if(specialization == null)
\r
236 specialization = new ValRef[arity];
\r
237 specialization[i] = parameters[i];
\r
241 if(specialization != null)
\r
242 specialize(context, apply, specialization);
\r
245 private void specialize(SSASimplificationContext context, LetApply apply,
\r
246 ValRef[] specialization) {
\r
247 /*System.out.println("=== SPECIALIZE ====================");
\r
248 System.out.println(apply);
\r
249 System.out.println("--------");
\r
250 System.out.println(definition);
\r
251 System.out.println("========");*/
\r
252 // *** Modify apply *******************************
\r
254 // Handle old parameters
\r
255 ValRef[] oldParameters = apply.getParameters();
\r
256 int newParameterCount = oldParameters.length - specialization.length;
\r
257 for(int i=0;i<specialization.length;++i)
\r
258 if(specialization[i] == null)
\r
259 ++newParameterCount;
\r
261 if(newParameterCount == 0) {
\r
262 // If apply would be degenerated, remove it
\r
263 apply.getTarget().replaceBy(apply.getFunction());
\r
267 // Create new parameter array
\r
268 ValRef[] newParameters = new ValRef[newParameterCount];
\r
270 for(int i=0;i<specialization.length;++i)
\r
271 if(specialization[i] == null)
\r
272 newParameters[k++] = oldParameters[i];
\r
274 oldParameters[i].remove();
\r
275 for(int i=specialization.length;i<oldParameters.length;++i)
\r
276 newParameters[k++] = oldParameters[i];
\r
278 apply.setParameters(newParameters);
\r
282 // *** Modify definition **************************
\r
284 SSABlock firstBlock = definition.getFirstBlock();
\r
285 BoundVar[] parameters = firstBlock.getParameters();
\r
286 ArrayList<BoundVar> newParameters = new ArrayList<BoundVar>(parameters.length);
\r
287 for(int i=0;i<specialization.length;++i)
\r
288 if(specialization[i] != null)
\r
289 parameters[i].replaceBy(specialization[i]);
\r
291 newParameters.add(parameters[i]);
\r
292 for(int i=specialization.length;i<parameters.length;++i)
\r
293 newParameters.add(parameters[i]);
\r
294 firstBlock.setParameters(newParameters.toArray(new BoundVar[newParameters.size()]));
\r
296 type = definition.getType();
\r
299 /*System.out.println(apply);
\r
300 System.out.println("--------");
\r
301 System.out.println(definition);*/
\r
302 context.markModified("SCLConstant.specialize");
\r
306 public String toString() {
\r
307 char c = name.name.charAt(0);
\r
308 if(Character.isJavaIdentifierStart(c) || name.name.charAt(0) == '(' || c == '[')
\r
311 return "(" + name.name + ")";
\r
315 public Name getName() {
\r
319 public Constant getBase() {
\r
323 public boolean isPrivate() {
\r
327 private boolean simplifyConstantFunction(SSASimplificationContext context) {
\r
328 ValRef constant = definition.isEqualToConstant();
\r
329 if(constant == null)
\r
331 Val binding = constant.getBinding();
\r
332 if(binding == this)
\r
334 if(binding instanceof Constant) {
\r
335 /*System.out.println(name + " -> " + constant.getBinding());
\r
336 System.out.println("replace: " + this);
\r
337 System.out.println("of type: " + this.getType());
\r
338 System.out.println("by: " + binding);
\r
339 System.out.println("of type: " + binding.getType());
\r
340 System.out.println("parameters: " + Types.toString(definition.getTypeParameters()));
\r
341 System.out.println("parameters2: " + Types.toString(constant.getTypeParameters()));
\r
342 System.out.println("private: " + isPrivate);*/
\r
344 definition.getTypeParameters(),
\r
345 constant.getTypeParameters());
\r
347 definition.destroy();
\r
348 context.removeConstant(name);
\r
350 context.markModified("SCLConstant.simplify-constant");
\r
356 public void simplify(SSASimplificationContext context) {
\r
357 if(!hasNoOccurences() /* TODO why this condition is needed? */) {
\r
358 if(simplifyConstantFunction(context))
\r
362 definition.tryToMakeMonadic(context);*/
\r
363 definition.simplify(context);
\r
364 if(inlineArity == Integer.MAX_VALUE && definition.isSimpleEnoughForInline()) {
\r
365 inlineArity = definition.getArity();
\r
366 inlinableDefinition = definition.copy();
\r
367 context.markModified("mark inlineable " + name);
\r
368 // FIXME this will make self calling function inlinable that may crash the compiler
\r
372 public void saveInlinableDefinition() {
\r
373 if(inlineArity < Integer.MAX_VALUE)
\r
374 inlinableDefinition = definition.copy();
\r