--- /dev/null
+package org.simantics.scl.compiler.constants;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+\r
+import org.simantics.scl.compiler.common.names.Name;\r
+import org.simantics.scl.compiler.common.names.Named;\r
+import org.simantics.scl.compiler.internal.codegen.optimization.Optimization;\r
+import org.simantics.scl.compiler.internal.codegen.optimization.OptimizationMap;\r
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;\r
+import org.simantics.scl.compiler.internal.codegen.references.Val;\r
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;\r
+import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions;\r
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;\r
+import org.simantics.scl.compiler.types.TVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+\r
+public class SCLConstant extends DelegateConstant implements Named {\r
+\r
+ public Name name; // Needed only for debugging\r
+ public SSAFunction definition;\r
+ public SSAFunction inlinableDefinition;\r
+ public int inlineArity = Integer.MAX_VALUE;\r
+ public int inlinePhaseMask = 0xffffffff;\r
+ public boolean isPrivate = false; \r
+ \r
+ public SCLConstant(Name name, Type type) {\r
+ super(type);\r
+ this.name = name;\r
+ }\r
+ \r
+ public void setInlineArity(int inlineArity, int inlinePhaseMask) {\r
+ this.inlineArity = inlineArity;\r
+ this.inlinePhaseMask = inlinePhaseMask;\r
+ //System.out.println(name + " " + inlineArity + " " + inlinePhaseMask);\r
+ }\r
+ \r
+ public void setPrivate(boolean isPrivate) {\r
+ this.isPrivate = isPrivate;\r
+ }\r
+ \r
+ public void setDefinition(SSAFunction definition) {\r
+ this.definition = definition;\r
+ }\r
+ \r
+ public SSAFunction getDefinition() {\r
+ return definition;\r
+ }\r
+\r
+ @Override\r
+ public void inline(SSASimplificationContext context, LetApply apply) {\r
+ if(inlineTailCallToSelf(context, apply)) {\r
+ return;\r
+ }\r
+ /*if(tryBetaReduce(context, apply)) {\r
+ return;\r
+ }*/\r
+ if(basicInline(context, apply)) {\r
+ return;\r
+ }\r
+ trySpecialize(context, apply);\r
+ \r
+ Optimization opt = OptimizationMap.OPTIMIZATIONS.get(name);\r
+ if(opt != null)\r
+ opt.inline(context, apply);\r
+ }\r
+\r
+ static int inlineCount = 0;\r
+ \r
+ private boolean canInlineInPhase(int phase) {\r
+ return ((inlinePhaseMask >> phase)&1) == 1;\r
+ }\r
+ \r
+ private boolean basicInline(SSASimplificationContext context, LetApply apply) {\r
+ if(!canInlineInPhase(context.getPhase())) {\r
+ //System.out.println("Cannot optimize " + name + " in phase " + context.getPhase());\r
+ return false;\r
+ }\r
+ ValRef functionRef = apply.getFunction();\r
+ ValRef[] parameters = apply.getParameters();\r
+ SSAFunction def = inlinableDefinition == null ? definition : inlinableDefinition;\r
+ if(parameters.length < inlineArity &&\r
+ (!isPrivate \r
+ || parameters.length != def.getArity() \r
+ || hasMoreThanOneOccurences()))\r
+ return false;\r
+ \r
+ //if(def.getArity() == 0)\r
+ // return false; // FIXME\r
+ \r
+ //System.out.println("basicInline: " + apply);\r
+ //System.out.println("def: " + def);\r
+ \r
+ if(isPrivate && !hasMoreThanOneOccurences())\r
+ context.removeConstant(name);\r
+ else\r
+ def = def.copy();\r
+ \r
+ if(parameters.length >= def.getArity()) {\r
+ if(parameters.length != def.getArity())\r
+ apply.split(def.getArity());\r
+ apply.inline(def);\r
+ context.markModified("SCLConstant.beta-constant " + getName());\r
+ }\r
+ else /*if(parameters.length < def.getArity())*/ {\r
+ def.applyTypes(functionRef.getTypeParameters());\r
+ def.apply(parameters);\r
+ \r
+ def.setTarget(apply.getTarget());\r
+ new LetFunctions(def).insertBefore(apply);\r
+\r
+ apply.remove();\r
+ context.markModified("SCLConstant.partial-beta-constant " + getName());\r
+ }\r
+ \r
+ /*Name newName = Name.create(name.module,\r
+ name.name + "_S" + (++inlineCount));\r
+ SCLConstant newConstant = new SCLConstant(newName, type);\r
+ newConstant.setPrivate(true);\r
+ newConstant.setDefinition(definition.copy()); */ \r
+ /*System.out.println("*** 1 *************************************");\r
+ System.out.println(definition);\r
+ System.out.println("*** 2 *************************************");\r
+ System.out.println(newConstant.definition);\r
+ \r
+ function.remove();\r
+ apply.setFunction(newConstant.createOccurrence(function.getTypeParameters()));\r
+ \r
+ context.addConstant(newConstant);\r
+ \r
+ context.markModified();\r
+ \r
+ newConstant.trySpecialize(context, apply);\r
+ */\r
+ \r
+ return true;\r
+ }\r
+\r
+ private boolean inlineTailCallToSelf(SSASimplificationContext context, LetApply apply) {\r
+ SSAFunction thisFunction = apply.getParent().getParent();\r
+ if(thisFunction != definition)\r
+ return false;\r
+ ValRef ref = apply.getTarget().getOccurrence();\r
+ if(ref == null || ref.getNext() != null)\r
+ return false;\r
+ if(!(ref.getParent() instanceof Jump))\r
+ return false;\r
+ Jump jump = (Jump)ref.getParent();\r
+ if(jump.getParameters().length != 1)\r
+ return false;\r
+ if(jump.getTarget().getBinding() != thisFunction.getReturnCont())\r
+ return false;\r
+ if(apply.getParameters().length != thisFunction.getArity())\r
+ return false;\r
+ \r
+ jump.getTarget().remove();\r
+ jump.setTarget(thisFunction.getFirstBlock().createOccurrence());\r
+ jump.setParameters(apply.getParameters());\r
+ \r
+ apply.getFunction().remove();\r
+ apply.detach();\r
+ \r
+ context.markModified("SCLConstant.simplify-tail-call");\r
+ \r
+ return true;\r
+ }\r
+\r
+ private void trySpecialize(SSASimplificationContext context, LetApply apply) {\r
+ if(!isPrivate)\r
+ return;\r
+ if(hasMoreThanOneOccurences())\r
+ return;\r
+ if(apply.getParent().getParent() == definition)\r
+ return;\r
+\r
+ // Specialization of type parameters\r
+ {\r
+ ValRef functionRef = apply.getFunction();\r
+ Type[] pValues = functionRef.getTypeParameters(); \r
+ boolean hasComplexTypes = false;\r
+ for(Type type : pValues)\r
+ if(!(Types.canonical(type) instanceof TVar)) {\r
+ hasComplexTypes = true;\r
+ break;\r
+ }\r
+ if(hasComplexTypes) { \r
+ /*PrintingContext pc = new PrintingContext();\r
+ pc.append(">> BEFORE >>\n");\r
+ definition.toString(pc);*/ \r
+ \r
+ TVar[] pVars = definition.getTypeParameters();\r
+ TVar[] pVarsTail;\r
+ if(pVars.length == pValues.length)\r
+ pVarsTail = TVar.EMPTY_ARRAY;\r
+ else {\r
+ pVarsTail = Arrays.copyOfRange(pVars, pValues.length, pVars.length);\r
+ pVars = Arrays.copyOf(pVars, pValues.length);\r
+ }\r
+ type = Types.instantiate(type, pValues);\r
+ /*pc.append("REPLACE: ");\r
+ pc.append(pVars);\r
+ pc.append(" -> ");\r
+ pc.append(pValues);\r
+ pc.append('\n');*/\r
+ definition.replace(pVars, pValues);\r
+ TVar[] newParameters = Types.freeVarsArray(pValues);\r
+ type = Types.forAll(newParameters, type);\r
+ functionRef.setTypeParameters(newParameters);\r
+ definition.setTypeParameters(Types.concat(newParameters, pVarsTail)); \r
+ \r
+ /*pc.append(">> AFTER >>\n");\r
+ definition.toString(pc);\r
+ System.out.println(pc);*/\r
+ context.markModified("SCLConstant.specialize-types");\r
+ }\r
+ }\r
+ \r
+ if(!definition.getFirstBlock().hasNoOccurences())\r
+ // TODO We can flex this requirement if all jumps to the first block\r
+ // give same values to the first block\r
+ return;\r
+ \r
+ // Specialization of parameters\r
+ ValRef[] parameters = apply.getParameters();\r
+ ValRef[] specialization = null;\r
+ int arity = Math.min(parameters.length, definition.getArity());\r
+ for(int i=0;i<arity;++i) {\r
+ Val val = parameters[i].getBinding();\r
+ if(val instanceof Constant) {\r
+ if(specialization == null)\r
+ specialization = new ValRef[arity];\r
+ specialization[i] = parameters[i];\r
+ }\r
+ }\r
+ \r
+ if(specialization != null)\r
+ specialize(context, apply, specialization);\r
+ }\r
+\r
+ private void specialize(SSASimplificationContext context, LetApply apply,\r
+ ValRef[] specialization) {\r
+ /*System.out.println("=== SPECIALIZE ====================");\r
+ System.out.println(apply);\r
+ System.out.println("--------");\r
+ System.out.println(definition);\r
+ System.out.println("========");*/\r
+ // *** Modify apply ******************************* \r
+ {\r
+ // Handle old parameters\r
+ ValRef[] oldParameters = apply.getParameters();\r
+ int newParameterCount = oldParameters.length - specialization.length;\r
+ for(int i=0;i<specialization.length;++i)\r
+ if(specialization[i] == null)\r
+ ++newParameterCount; \r
+\r
+ if(newParameterCount == 0) {\r
+ // If apply would be degenerated, remove it\r
+ apply.getTarget().replaceBy(apply.getFunction());\r
+ apply.remove();\r
+ } \r
+ else {\r
+ // Create new parameter array\r
+ ValRef[] newParameters = new ValRef[newParameterCount];\r
+ int k=0;\r
+ for(int i=0;i<specialization.length;++i)\r
+ if(specialization[i] == null)\r
+ newParameters[k++] = oldParameters[i];\r
+ else\r
+ oldParameters[i].remove(); \r
+ for(int i=specialization.length;i<oldParameters.length;++i)\r
+ newParameters[k++] = oldParameters[i];\r
+ \r
+ apply.setParameters(newParameters);\r
+ }\r
+ }\r
+ \r
+ // *** Modify definition ************************** \r
+ {\r
+ SSABlock firstBlock = definition.getFirstBlock();\r
+ BoundVar[] parameters = firstBlock.getParameters();\r
+ ArrayList<BoundVar> newParameters = new ArrayList<BoundVar>(parameters.length); \r
+ for(int i=0;i<specialization.length;++i)\r
+ if(specialization[i] != null)\r
+ parameters[i].replaceBy(specialization[i]);\r
+ else\r
+ newParameters.add(parameters[i]);\r
+ for(int i=specialization.length;i<parameters.length;++i)\r
+ newParameters.add(parameters[i]);\r
+ firstBlock.setParameters(newParameters.toArray(new BoundVar[newParameters.size()]));\r
+ \r
+ type = definition.getType();\r
+ }\r
+ \r
+ /*System.out.println(apply);\r
+ System.out.println("--------");\r
+ System.out.println(definition);*/\r
+ context.markModified("SCLConstant.specialize"); \r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ char c = name.name.charAt(0);\r
+ if(Character.isJavaIdentifierStart(c) || name.name.charAt(0) == '(' || c == '[')\r
+ return name.name;\r
+ else\r
+ return "(" + name.name + ")";\r
+ }\r
+\r
+ @Override\r
+ public Name getName() {\r
+ return name;\r
+ }\r
+\r
+ public Constant getBase() {\r
+ return base;\r
+ }\r
+ \r
+ public boolean isPrivate() {\r
+ return isPrivate;\r
+ }\r
+\r
+ private boolean simplifyConstantFunction(SSASimplificationContext context) {\r
+ ValRef constant = definition.isEqualToConstant();\r
+ if(constant == null)\r
+ return false;\r
+ Val binding = constant.getBinding();\r
+ if(binding == this)\r
+ return false;\r
+ if(binding instanceof Constant) {\r
+ /*System.out.println(name + " -> " + constant.getBinding());\r
+ System.out.println("replace: " + this);\r
+ System.out.println("of type: " + this.getType());\r
+ System.out.println("by: " + binding);\r
+ System.out.println("of type: " + binding.getType());\r
+ System.out.println("parameters: " + Types.toString(definition.getTypeParameters()));\r
+ System.out.println("parameters2: " + Types.toString(constant.getTypeParameters()));\r
+ System.out.println("private: " + isPrivate);*/ \r
+ replaceBy(binding,\r
+ definition.getTypeParameters(), \r
+ constant.getTypeParameters()); \r
+ if(isPrivate) {\r
+ definition.destroy();\r
+ context.removeConstant(name);\r
+ }\r
+ context.markModified("SCLConstant.simplify-constant");\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ public void simplify(SSASimplificationContext context) {\r
+ if(!hasNoOccurences() /* TODO why this condition is needed? */) {\r
+ if(simplifyConstantFunction(context))\r
+ return;\r
+ }\r
+ /*if(isPrivate)\r
+ definition.tryToMakeMonadic(context);*/\r
+ definition.simplify(context);\r
+ if(inlineArity == Integer.MAX_VALUE && definition.isSimpleEnoughForInline()) {\r
+ inlineArity = definition.getArity();\r
+ inlinableDefinition = definition.copy();\r
+ context.markModified("mark inlineable " + name);\r
+ // FIXME this will make self calling function inlinable that may crash the compiler\r
+ }\r
+ }\r
+\r
+ public void saveInlinableDefinition() {\r
+ if(inlineArity < Integer.MAX_VALUE)\r
+ inlinableDefinition = definition.copy();\r
+ }\r
+}\r