X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fconstants%2FSCLConstant.java;fp=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fconstants%2FSCLConstant.java;h=a4c47ea76a8cb55a8bf39288cb9acbbd8d5c59ae;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java new file mode 100644 index 000000000..a4c47ea76 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstant.java @@ -0,0 +1,376 @@ +package org.simantics.scl.compiler.constants; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.simantics.scl.compiler.common.names.Name; +import org.simantics.scl.compiler.common.names.Named; +import org.simantics.scl.compiler.internal.codegen.optimization.Optimization; +import org.simantics.scl.compiler.internal.codegen.optimization.OptimizationMap; +import org.simantics.scl.compiler.internal.codegen.references.BoundVar; +import org.simantics.scl.compiler.internal.codegen.references.Val; +import org.simantics.scl.compiler.internal.codegen.references.ValRef; +import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock; +import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction; +import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump; +import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply; +import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions; +import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext; +import org.simantics.scl.compiler.types.TVar; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; + +public class SCLConstant extends DelegateConstant implements Named { + + public Name name; // Needed only for debugging + public SSAFunction definition; + public SSAFunction inlinableDefinition; + public int inlineArity = Integer.MAX_VALUE; + public int inlinePhaseMask = 0xffffffff; + public boolean isPrivate = false; + + public SCLConstant(Name name, Type type) { + super(type); + this.name = name; + } + + public void setInlineArity(int inlineArity, int inlinePhaseMask) { + this.inlineArity = inlineArity; + this.inlinePhaseMask = inlinePhaseMask; + //System.out.println(name + " " + inlineArity + " " + inlinePhaseMask); + } + + public void setPrivate(boolean isPrivate) { + this.isPrivate = isPrivate; + } + + public void setDefinition(SSAFunction definition) { + this.definition = definition; + } + + public SSAFunction getDefinition() { + return definition; + } + + @Override + public void inline(SSASimplificationContext context, LetApply apply) { + if(inlineTailCallToSelf(context, apply)) { + return; + } + /*if(tryBetaReduce(context, apply)) { + return; + }*/ + if(basicInline(context, apply)) { + return; + } + trySpecialize(context, apply); + + Optimization opt = OptimizationMap.OPTIMIZATIONS.get(name); + if(opt != null) + opt.inline(context, apply); + } + + static int inlineCount = 0; + + private boolean canInlineInPhase(int phase) { + return ((inlinePhaseMask >> phase)&1) == 1; + } + + private boolean basicInline(SSASimplificationContext context, LetApply apply) { + if(!canInlineInPhase(context.getPhase())) { + //System.out.println("Cannot optimize " + name + " in phase " + context.getPhase()); + return false; + } + ValRef functionRef = apply.getFunction(); + ValRef[] parameters = apply.getParameters(); + SSAFunction def = inlinableDefinition == null ? definition : inlinableDefinition; + if(parameters.length < inlineArity && + (!isPrivate + || parameters.length != def.getArity() + || hasMoreThanOneOccurences())) + return false; + + //if(def.getArity() == 0) + // return false; // FIXME + + //System.out.println("basicInline: " + apply); + //System.out.println("def: " + def); + + if(isPrivate && !hasMoreThanOneOccurences()) + context.removeConstant(name); + else + def = def.copy(); + + if(parameters.length >= def.getArity()) { + if(parameters.length != def.getArity()) + apply.split(def.getArity()); + apply.inline(def); + context.markModified("SCLConstant.beta-constant " + getName()); + } + else /*if(parameters.length < def.getArity())*/ { + def.applyTypes(functionRef.getTypeParameters()); + def.apply(parameters); + + def.setTarget(apply.getTarget()); + new LetFunctions(def).insertBefore(apply); + + apply.remove(); + context.markModified("SCLConstant.partial-beta-constant " + getName()); + } + + /*Name newName = Name.create(name.module, + name.name + "_S" + (++inlineCount)); + SCLConstant newConstant = new SCLConstant(newName, type); + newConstant.setPrivate(true); + newConstant.setDefinition(definition.copy()); */ + /*System.out.println("*** 1 *************************************"); + System.out.println(definition); + System.out.println("*** 2 *************************************"); + System.out.println(newConstant.definition); + + function.remove(); + apply.setFunction(newConstant.createOccurrence(function.getTypeParameters())); + + context.addConstant(newConstant); + + context.markModified(); + + newConstant.trySpecialize(context, apply); + */ + + return true; + } + + private boolean inlineTailCallToSelf(SSASimplificationContext context, LetApply apply) { + SSAFunction thisFunction = apply.getParent().getParent(); + if(thisFunction != definition) + return false; + ValRef ref = apply.getTarget().getOccurrence(); + if(ref == null || ref.getNext() != null) + return false; + if(!(ref.getParent() instanceof Jump)) + return false; + Jump jump = (Jump)ref.getParent(); + if(jump.getParameters().length != 1) + return false; + if(jump.getTarget().getBinding() != thisFunction.getReturnCont()) + return false; + if(apply.getParameters().length != thisFunction.getArity()) + return false; + + jump.getTarget().remove(); + jump.setTarget(thisFunction.getFirstBlock().createOccurrence()); + jump.setParameters(apply.getParameters()); + + apply.getFunction().remove(); + apply.detach(); + + context.markModified("SCLConstant.simplify-tail-call"); + + return true; + } + + private void trySpecialize(SSASimplificationContext context, LetApply apply) { + if(!isPrivate) + return; + if(hasMoreThanOneOccurences()) + return; + if(apply.getParent().getParent() == definition) + return; + + // Specialization of type parameters + { + ValRef functionRef = apply.getFunction(); + Type[] pValues = functionRef.getTypeParameters(); + boolean hasComplexTypes = false; + for(Type type : pValues) + if(!(Types.canonical(type) instanceof TVar)) { + hasComplexTypes = true; + break; + } + if(hasComplexTypes) { + /*PrintingContext pc = new PrintingContext(); + pc.append(">> BEFORE >>\n"); + definition.toString(pc);*/ + + TVar[] pVars = definition.getTypeParameters(); + TVar[] pVarsTail; + if(pVars.length == pValues.length) + pVarsTail = TVar.EMPTY_ARRAY; + else { + pVarsTail = Arrays.copyOfRange(pVars, pValues.length, pVars.length); + pVars = Arrays.copyOf(pVars, pValues.length); + } + type = Types.instantiate(type, pValues); + /*pc.append("REPLACE: "); + pc.append(pVars); + pc.append(" -> "); + pc.append(pValues); + pc.append('\n');*/ + definition.replace(pVars, pValues); + TVar[] newParameters = Types.freeVarsArray(pValues); + type = Types.forAll(newParameters, type); + functionRef.setTypeParameters(newParameters); + definition.setTypeParameters(Types.concat(newParameters, pVarsTail)); + + /*pc.append(">> AFTER >>\n"); + definition.toString(pc); + System.out.println(pc);*/ + context.markModified("SCLConstant.specialize-types"); + } + } + + if(!definition.getFirstBlock().hasNoOccurences()) + // TODO We can flex this requirement if all jumps to the first block + // give same values to the first block + return; + + // Specialization of parameters + ValRef[] parameters = apply.getParameters(); + ValRef[] specialization = null; + int arity = Math.min(parameters.length, definition.getArity()); + for(int i=0;i newParameters = new ArrayList(parameters.length); + for(int i=0;i " + constant.getBinding()); + System.out.println("replace: " + this); + System.out.println("of type: " + this.getType()); + System.out.println("by: " + binding); + System.out.println("of type: " + binding.getType()); + System.out.println("parameters: " + Types.toString(definition.getTypeParameters())); + System.out.println("parameters2: " + Types.toString(constant.getTypeParameters())); + System.out.println("private: " + isPrivate);*/ + replaceBy(binding, + definition.getTypeParameters(), + constant.getTypeParameters()); + if(isPrivate) { + definition.destroy(); + context.removeConstant(name); + } + context.markModified("SCLConstant.simplify-constant"); + return true; + } + return false; + } + + public void simplify(SSASimplificationContext context) { + if(!hasNoOccurences() /* TODO why this condition is needed? */) { + if(simplifyConstantFunction(context)) + return; + } + /*if(isPrivate) + definition.tryToMakeMonadic(context);*/ + definition.simplify(context); + if(inlineArity == Integer.MAX_VALUE && definition.isSimpleEnoughForInline()) { + inlineArity = definition.getArity(); + inlinableDefinition = definition.copy(); + context.markModified("mark inlineable " + name); + // FIXME this will make self calling function inlinable that may crash the compiler + } + } + + public void saveInlinableDefinition() { + if(inlineArity < Integer.MAX_VALUE) + inlinableDefinition = definition.copy(); + } +}