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