-package org.simantics.scl.compiler.internal.codegen.ssa.statements;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-\r
-import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
-import org.simantics.scl.compiler.constants.Constant;\r
-import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;\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.SSAExit;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.binders.BoundVarBinder;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.exits.Switch;\r
-import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;\r
-import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;\r
-import org.simantics.scl.compiler.top.SCLCompilerConfiguration;\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
-import org.simantics.scl.compiler.types.exceptions.MatchException;\r
-import org.simantics.scl.compiler.types.util.MultiFunction;\r
-\r
-public class LetApply extends LetStatement implements ValRefBinder {\r
- private ValRef function;\r
- private ValRef[] parameters;\r
- Type effect;\r
- \r
- public LetApply(BoundVar target, Type effect, ValRef function, ValRef ... parameters) {\r
- super(target);\r
- if(SCLCompilerConfiguration.DEBUG) {\r
- if(effect == null)\r
- throw new InternalCompilerError();\r
- if(function.getBinding() == null)\r
- throw new InternalCompilerError();\r
- }\r
- this.setFunction(function);\r
- this.setParameters(parameters);\r
- this.effect = Types.canonical(effect);\r
- }\r
-\r
- public void push(MethodBuilder mb) {\r
- //mb.getCodeBuilder().mapLineNumber(lineNumber);\r
- Val f = getFunction().getBinding();\r
- Val[] ps = ValRef.getBindings(getParameters());\r
- if(f instanceof Constant) {\r
- Constant cf = (Constant)f;\r
- Type returnType = cf.apply(mb, getFunction().getTypeParameters(), ps);\r
- if(Types.isBoxed(returnType))\r
- mb.unbox(target.getType());\r
- }\r
- else { \r
- mb.push(f, f.getType());\r
- mb.pushBoxed(ps);\r
- mb.genericApply(ps.length);\r
- mb.unbox(target.getType());\r
- }\r
- }\r
- \r
- @Override\r
- public void generateCode(MethodBuilder mb) {\r
- if(!target.generateOnFly) {\r
- push(mb);\r
- mb.store(target);\r
- }\r
- }\r
-\r
- @Override\r
- public void toString(PrintingContext context) {\r
- if(determineGenerateOnFly())\r
- context.addInlineExpression(target, this);\r
- else\r
- toStringAux(context);\r
- }\r
- \r
- private void toStringAux(PrintingContext context) {\r
- context.indentation();\r
- context.append(target);\r
- context.append("(" + target.occurrenceCount() + ")");\r
- context.append(" = ");\r
- bodyToString(context);\r
- context.append('\n');\r
- \r
- }\r
- \r
- public void bodyToString(PrintingContext context) {\r
- if(context.getErrorMarker() == this)\r
- context.append("!> ");\r
- if(hasEffect()) {\r
- context.append("<");\r
- context.append(effect);\r
- context.append("> ");\r
- }\r
- context.append(getFunction());\r
- for(ValRef parameter : getParameters()) {\r
- context.append(' ');\r
- context.append(parameter);\r
- }\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- PrintingContext context = new PrintingContext();\r
- toStringAux(context);\r
- return context.toString();\r
- }\r
-\r
- @Override\r
- public void validate(SSAValidationContext context) {\r
- context.validate(target);\r
- if(target.getParent() != this)\r
- throw new InternalCompilerError();\r
- context.validate(function);\r
- if(function.getParent() != this)\r
- throw new InternalCompilerError();\r
- for(ValRef parameter : parameters) {\r
- context.validate(parameter);\r
- if(parameter.getParent() != this)\r
- throw new InternalCompilerError();\r
- }\r
- //if(parameters.length == 0)\r
- // throw new InternalCompilerError();\r
- \r
- \r
- MultiFunction mFun;\r
- try {\r
- mFun = Types.matchFunction(getFunction().getType(), getParameters().length);\r
- } catch (MatchException e) {\r
- context.setErrorMarker(this);\r
- throw new InternalCompilerError();\r
- }\r
- for(int i=0;i<getParameters().length;++i)\r
- context.assertSubsumes(this, getParameters()[i].getType(), mFun.parameterTypes[i]);\r
- context.assertSubsumes(this, target.getType(), mFun.returnType);\r
- context.assertEqualsEffect(this, effect, mFun.effect);\r
- }\r
-\r
- @Override\r
- public void destroy() {\r
- getFunction().remove();\r
- for(ValRef parameter : getParameters())\r
- parameter.remove();\r
- }\r
- \r
- @Override\r
- public void simplify(SSASimplificationContext context) {\r
- if(target.hasNoOccurences() && !hasEffect()) {\r
- remove();\r
- context.markModified("LetApply.dead-let-statement");\r
- return;\r
- }\r
- Val functionVal = getFunction().getBinding();\r
- if(functionVal instanceof BoundVar) {\r
- BoundVarBinder parent_ = ((BoundVar)functionVal).parent;\r
- if(parent_ instanceof SSAFunction) {\r
- SSAFunction function = (SSAFunction)parent_;\r
- if(functionVal.hasMoreThanOneOccurences())\r
- return;\r
- if(getParameters().length < function.getArity())\r
- return;\r
- if(getParameters().length > function.getArity())\r
- split(function.getArity());\r
- inline(function);\r
- function.detach();\r
- context.markModified("LetApply.beta-lambda");\r
- }\r
- else if(parent_ instanceof LetApply) {\r
- LetApply apply = (LetApply)parent_;\r
- if(apply.hasEffect())\r
- return;\r
- boolean hasJustOneOccurence = !functionVal.hasMoreThanOneOccurences();\r
- if((hasJustOneOccurence && apply.getParent() == getParent()) ||\r
- apply.isPartial()) {\r
- if(hasJustOneOccurence) {\r
- apply.detach();\r
- setFunction(apply.getFunction());\r
- setParameters(ValRef.concat(apply.getParameters(), getParameters()));\r
- }\r
- else {\r
- setFunction(apply.getFunction().copy());\r
- setParameters(ValRef.concat(ValRef.copy(apply.getParameters()), getParameters()));\r
- }\r
- context.markModified("LetApply.merge-applications");\r
- }\r
- }\r
- else if(parent_ instanceof SSABlock) {\r
- SSABlock parent = getParent();\r
- if(parent_ != parent)\r
- return;\r
- if(parent.getFirstStatement() != this)\r
- return;\r
- if(!parent.hasMoreThanOneOccurences())\r
- return; // We stop here, because situation can be handled by better transformations\r
- if(functionVal.hasMoreThanOneOccurences())\r
- return;\r
- // We have now the following situation:\r
- // [c] ... f ... =\r
- // x = f ... \r
- // * this application is the only reference to f\r
- // * there are multiple references to [c]\r
- for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext())\r
- if(!(ref.getParent() instanceof Jump))\r
- return;\r
- \r
- // Finds the position of the functionVal in the parameter list of \r
- // the parent block.\r
- int position;\r
- for(position=0;position<parent.getParameters().length;++position)\r
- if(parent.getParameters()[position] == functionVal)\r
- break;\r
- if(position == parent.getParameters().length)\r
- throw new InternalCompilerError();\r
- \r
- // Do tranformation\r
- for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext()) {\r
- Jump jump = (Jump)ref.getParent();\r
- SSABlock block = jump.getParent();\r
- \r
- BoundVar newTarget = new BoundVar(target.getType());\r
- block.addStatement(new LetApply(newTarget, effect, jump.getParameter(position), ValRef.copy(parameters)));\r
- jump.setParameter(position, newTarget.createOccurrence());\r
- }\r
- \r
- parent.setParameter(position, target);\r
- remove();\r
- context.markModified("LetApply.hoist-apply");\r
- }\r
- }\r
- else if(functionVal instanceof Constant) {\r
- ((Constant)functionVal).inline(context, this);\r
- }\r
- }\r
- \r
- public boolean isPartial() {\r
- return parameters.length < function.getBinding().getEffectiveArity();\r
- }\r
-\r
- /**\r
- * Removes apply if it does not have parameters.\r
- */\r
- public void removeDegenerated() {\r
- if(getParameters().length == 0) {\r
- target.replaceBy(getFunction());\r
- getFunction().remove();\r
- detach();\r
- }\r
- }\r
-\r
- public boolean determineGenerateOnFly() {\r
- if(hasEffect())\r
- return false;\r
- ValRef ref = target.getOccurrence();\r
- if(ref == null || ref.getNext() != null)\r
- return false;\r
- Object parent = ref.getParent();\r
- if(parent instanceof SSAStatement) {\r
- if(((SSAStatement)parent).getParent() != getParent())\r
- return false;\r
- }\r
- else if(parent instanceof SSAExit) {\r
- if(((SSAExit)parent).getParent() != getParent())\r
- return false;\r
- if(parent instanceof Switch)\r
- return false;\r
- }\r
- else\r
- return false;\r
- return true;\r
- }\r
- \r
- @Override\r
- public void markGenerateOnFly() { \r
- target.generateOnFly = determineGenerateOnFly();\r
- }\r
-\r
- public ValRef getFunction() {\r
- return function;\r
- }\r
-\r
- public void setFunction(ValRef function) {\r
- this.function = function;\r
- function.setParent(this);\r
- }\r
-\r
- public ValRef[] getParameters() {\r
- return parameters;\r
- }\r
-\r
- public void setParameters(ValRef[] parameters) {\r
- /*if(SCLCompilerConfiguration.DEBUG)\r
- if(parameters.length == 0)\r
- throw new InternalCompilerError();*/\r
- this.parameters = parameters;\r
- for(ValRef parameter : parameters)\r
- parameter.setParent(this);\r
- }\r
- \r
- @Override\r
- public SSAStatement copy(CopyContext context) {\r
- LetApply result = new LetApply(context.copy(target), \r
- context.copyType(effect),\r
- context.copy(function), \r
- context.copy(parameters));\r
- return result;\r
- }\r
- \r
- @Override\r
- public void replace(TVar[] vars, Type[] replacements) {\r
- target.replace(vars, replacements);\r
- function.replace(vars, replacements);\r
- effect = effect.replace(vars, replacements);\r
- for(ValRef parameter : parameters)\r
- parameter.replace(vars, replacements);\r
- }\r
- \r
- /**\r
- * Inlines the application by the given function.\r
- * It is assumed that the function has the same number\r
- * of parameters as this one and there are no other \r
- * references to the function (copy function before\r
- * inlining if necessary).\r
- */\r
- public void inline(SSAFunction function) {\r
- if(function.getArity() != parameters.length)\r
- throw new InternalCompilerError(); \r
- \r
- SSABlock headBlock = getParent();\r
- SSAFunction thisFunction = headBlock.getParent();\r
- \r
- /*System.out.println("--- INLINING -------------------------------");\r
- System.out.println(thisFunction);\r
- System.out.println("Function name: " + getFunction().getBinding());\r
- System.out.println("++++++++++++++++++++++++++++++++++++++++++++");\r
- System.out.println(function); \r
- */\r
- \r
- if(this.function.getTypeParameters().length > 0) {\r
- /*if(function.getParent() != null) {\r
- PrintingContext pc = new PrintingContext();\r
- pc.append("----------------------------\n");\r
- function.getParent().getParentFunction().toString(pc);\r
- pc.append("\n----\n");\r
- function.toString(pc);\r
- pc.append("\n");\r
- pc.append(function.getTypeParameters());\r
- pc.append(" -> ");\r
- pc.append(this.function.getTypeParameters());\r
- System.out.println(pc.toString());\r
- }*/\r
- function.replace(function.getTypeParameters(), this.function.getTypeParameters());\r
- }\r
-\r
- if(getPrev() != null)\r
- getPrev().setAsLastStatement();\r
- else\r
- headBlock.removeStatements();\r
- \r
- // Create tail block\r
- SSABlock tailBlock = new SSABlock(new BoundVar[] {target});\r
- thisFunction.addBlock(tailBlock);\r
- {\r
- SSAStatement stat = getNext();\r
- while(stat != null) {\r
- SSAStatement temp = stat.getNext();\r
- tailBlock.addStatement(stat);\r
- stat = temp;\r
- }\r
- }\r
- tailBlock.setExit(headBlock.getExit());\r
- \r
- // Merge blocks \r
- thisFunction.mergeBlocks(function); \r
- \r
- headBlock.setExit(new Jump(function.getFirstBlock().createOccurrence(), \r
- parameters));\r
- function.getReturnCont().replaceWith(tailBlock);\r
-\r
- this.function.remove();\r
- // Note: No need to remove or detach this statement anymore\r
- \r
- // TODO remove function\r
- /*\r
- System.out.println("============================================");\r
- System.out.println(thisFunction);\r
- */\r
- }\r
-\r
- @Override\r
- public void collectFreeVariables(SSAFunction parentFunction,\r
- ArrayList<ValRef> vars) {\r
- function.collectFreeVariables(parentFunction, vars);\r
- for(ValRef parameter : parameters)\r
- parameter.collectFreeVariables(parentFunction, vars);\r
- }\r
- \r
- @Override\r
- public void replaceByApply(ValRef valRef, Val newFunction, Type[] typeParameters, Val[] parameters) {\r
- if(function == valRef) {\r
- valRef.remove();\r
- setFunction(newFunction.createOccurrence(typeParameters));\r
- setParameters(ValRef.concat(ValRef.createOccurrences(parameters), this.parameters));\r
- }\r
- else\r
- super.replaceByApply(valRef, newFunction, typeParameters, parameters);\r
- }\r
-\r
- /**\r
- * Splits this application into two applications where the first has\r
- * the arity given as a parameter and the new application inserted \r
- * after this statement has the rest of the parameters.\r
- */\r
- public void split(int arity) {\r
- if(arity == parameters.length)\r
- return;\r
- if(arity > parameters.length)\r
- throw new InternalCompilerError();\r
- ValRef[] firstHalf = arity == 0 ? ValRef.EMPTY_ARRAY : Arrays.copyOf(parameters, arity);\r
- ValRef[] secondHalf = arity == parameters.length ? ValRef.EMPTY_ARRAY : Arrays.copyOfRange(parameters, arity, parameters.length);\r
- BoundVar newVar;\r
- try {\r
- MultiFunction mfun = Types.matchFunction(function.getType(), arity);\r
- newVar = new BoundVar(mfun.returnType);\r
- } catch (MatchException e) {\r
- throw new InternalCompilerError();\r
- }\r
- LetApply newApply = new LetApply(target, effect, \r
- newVar.createOccurrence(), secondHalf);\r
- newApply.insertAfter(this);\r
- effect = Types.NO_EFFECTS;\r
- setTarget(newVar);\r
- setParameters(firstHalf);\r
- }\r
- \r
- /**\r
- * True, if the application may have side effects.\r
- */\r
- public boolean hasEffect() {\r
- return effect != Types.NO_EFFECTS;\r
- }\r
-\r
- public void updateEffect() {\r
- try {\r
- MultiFunction mFun = Types.matchFunction(function.getType(), parameters.length);\r
- this.effect = mFun.effect;\r
- } catch (MatchException e) {\r
- throw new InternalCompilerError(e);\r
- }\r
- }\r
- \r
- @Override\r
- public void prepare(MethodBuilder mb) {\r
- function.getBinding().prepare(mb);\r
- }\r
-}\r
+package org.simantics.scl.compiler.internal.codegen.ssa.statements;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.constants.SCLConstant;
+import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
+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.SSAExit;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.BoundVarBinder;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
+import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;
+import org.simantics.scl.compiler.internal.codegen.ssa.exits.Switch;
+import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
+import org.simantics.scl.compiler.types.util.MultiFunction;
+
+public class LetApply extends LetStatement implements ValRefBinder {
+ private ValRef function;
+ private ValRef[] parameters;
+ Type effect;
+
+ public LetApply(BoundVar target, Type effect, ValRef function, ValRef ... parameters) {
+ super(target);
+ if(SCLCompilerConfiguration.DEBUG) {
+ if(effect == null)
+ throw new InternalCompilerError();
+ if(function.getBinding() == null)
+ throw new InternalCompilerError();
+ }
+ this.setFunction(function);
+ this.setParameters(parameters);
+ this.effect = Types.canonical(effect);
+ }
+
+ public void push(MethodBuilder mb) {
+ //mb.getCodeBuilder().mapLineNumber(lineNumber);
+ Val f = getFunction().getBinding();
+ Val[] ps = ValRef.getBindings(getParameters());
+ if(f instanceof Constant) {
+ Constant cf = (Constant)f;
+ Type returnType = cf.apply(mb, getFunction().getTypeParameters(), ps);
+ if(Types.isBoxed(returnType))
+ mb.unbox(target.getType());
+ }
+ else {
+ mb.push(f, f.getType());
+ mb.pushBoxed(ps);
+ mb.genericApply(ps.length);
+ mb.unbox(target.getType());
+ }
+ }
+
+ @Override
+ public void generateCode(MethodBuilder mb) {
+ if(!target.generateOnFly) {
+ push(mb);
+ mb.store(target);
+ }
+ }
+
+ @Override
+ public void toString(PrintingContext context) {
+ if(/*target.getLabel() == null &&*/ determineGenerateOnFly())
+ context.addInlineExpression(target, this);
+ else
+ toStringAux(context);
+ }
+
+ private void toStringAux(PrintingContext context) {
+ context.indentation();
+ context.append(target);
+ context.append("(" + target.occurrenceCount() + ")");
+ context.append(" = ");
+ bodyToString(context);
+ context.append('\n');
+
+ }
+
+ public void bodyToString(PrintingContext context) {
+ if(context.getErrorMarker() == this)
+ context.append("!> ");
+ if(hasEffect()) {
+ context.append("<");
+ context.append(effect);
+ context.append("> ");
+ }
+ context.append(getFunction());
+ for(ValRef parameter : getParameters()) {
+ context.append(' ');
+ context.append(parameter);
+ }
+ }
+
+ @Override
+ public String toString() {
+ PrintingContext context = new PrintingContext();
+ toStringAux(context);
+ return context.toString();
+ }
+
+ @Override
+ public void validate(SSAValidationContext context) {
+ context.validate(target);
+ if(target.getParent() != this)
+ throw new InternalCompilerError();
+ context.validate(function);
+ if(function.getParent() != this)
+ throw new InternalCompilerError();
+ for(ValRef parameter : parameters) {
+ context.validate(parameter);
+ if(parameter.getParent() != this)
+ throw new InternalCompilerError();
+ }
+ //if(parameters.length == 0)
+ // throw new InternalCompilerError();
+
+
+ MultiFunction mFun;
+ try {
+ mFun = Types.matchFunction(getFunction().getType(), getParameters().length);
+ } catch (MatchException e) {
+ context.setErrorMarker(this);
+ throw new InternalCompilerError();
+ }
+ for(int i=0;i<getParameters().length;++i)
+ context.assertSubsumes(this, getParameters()[i].getType(), mFun.parameterTypes[i]);
+ context.assertSubsumes(this, target.getType(), mFun.returnType);
+ context.assertEqualsEffect(this, effect, mFun.effect);
+ }
+
+ @Override
+ public void destroy() {
+ getFunction().remove();
+ for(ValRef parameter : getParameters())
+ parameter.remove();
+ }
+
+ @Override
+ public void simplify(SSASimplificationContext context) {
+ if(target.hasNoOccurences() && !hasEffect()) {
+ remove();
+ context.markModified("LetApply.dead-let-statement");
+ return;
+ }
+ // TODO this is quite heavy way for inlining constants
+ for(int i=0;i<parameters.length;++i) {
+ ValRef parameter = parameters[i];
+ Val value = parameter.getBinding();
+ if(!(value instanceof SCLConstant))
+ continue;
+ SCLConstant constant = (SCLConstant)value;
+ if(constant.inlineArity != 0)
+ continue;
+ SSAFunction definition = constant.definition;
+ SSABlock block = definition.getFirstBlock();
+ if(block.getFirstStatement() != null || !(block.getExit() instanceof Jump))
+ continue;
+ Jump jump = (Jump)block.getExit();
+ if(jump.getTarget().getBinding() != definition.getReturnCont())
+ continue;
+ if(jump.getParameter(0).getTypeParameters().length > 0)
+ continue;
+ parameter.replaceBy(jump.getParameter(0).getBinding());
+ }
+ Val functionVal = getFunction().getBinding();
+ if(functionVal instanceof BoundVar) {
+ BoundVarBinder parent_ = ((BoundVar)functionVal).parent;
+ if(parent_ instanceof SSAFunction) {
+ SSAFunction function = (SSAFunction)parent_;
+ if(functionVal.hasMoreThanOneOccurences())
+ return;
+ if(getParameters().length < function.getArity())
+ return;
+ if(getParameters().length > function.getArity())
+ split(function.getArity());
+ inline(function);
+ function.detach();
+ context.markModified("LetApply.beta-lambda");
+ }
+ else if(parent_ instanceof LetApply) {
+ LetApply apply = (LetApply)parent_;
+ if(apply.hasEffect())
+ return;
+ boolean hasJustOneOccurence = !functionVal.hasMoreThanOneOccurences();
+ if((hasJustOneOccurence && apply.getParent() == getParent()) ||
+ apply.isPartial()) {
+ if(hasJustOneOccurence) {
+ apply.detach();
+ setFunction(apply.getFunction());
+ setParameters(ValRef.concat(apply.getParameters(), getParameters()));
+ }
+ else {
+ setFunction(apply.getFunction().copy());
+ setParameters(ValRef.concat(ValRef.copy(apply.getParameters()), getParameters()));
+ }
+ context.markModified("LetApply.merge-applications");
+ }
+ }
+ else if(parent_ instanceof SSABlock) {
+ SSABlock parent = getParent();
+ if(parent_ != parent)
+ return;
+ if(parent.getFirstStatement() != this)
+ return;
+ if(!parent.hasMoreThanOneOccurences())
+ return; // We stop here, because situation can be handled by better transformations
+ if(functionVal.hasMoreThanOneOccurences())
+ return;
+ // We have now the following situation:
+ // [c] ... f ... =
+ // x = f ...
+ // * this application is the only reference to f
+ // * there are multiple references to [c]
+ for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext())
+ if(!(ref.getParent() instanceof Jump))
+ return;
+
+ // Finds the position of the functionVal in the parameter list of
+ // the parent block.
+ int position;
+ for(position=0;position<parent.getParameters().length;++position)
+ if(parent.getParameters()[position] == functionVal)
+ break;
+ if(position == parent.getParameters().length)
+ throw new InternalCompilerError();
+
+ // Do tranformation
+ for(ContRef ref = parent.getOccurrence();ref != null; ref = ref.getNext()) {
+ Jump jump = (Jump)ref.getParent();
+ SSABlock block = jump.getParent();
+
+ BoundVar newTarget = new BoundVar(target.getType());
+ block.addStatement(new LetApply(newTarget, effect, jump.getParameter(position), ValRef.copy(parameters)));
+ jump.setParameter(position, newTarget.createOccurrence());
+ }
+
+ parent.setParameter(position, target);
+ remove();
+ context.markModified("LetApply.hoist-apply");
+ }
+ }
+ else if(functionVal instanceof Constant) {
+ ((Constant)functionVal).inline(context, this);
+ }
+ }
+
+ public boolean isPartial() {
+ return parameters.length < function.getBinding().getEffectiveArity();
+ }
+
+ /**
+ * Removes apply if it does not have parameters.
+ */
+ public void removeDegenerated() {
+ if(getParameters().length == 0) {
+ target.replaceBy(getFunction());
+ getFunction().remove();
+ detach();
+ }
+ }
+
+ public boolean determineGenerateOnFly() {
+ if(hasEffect())
+ return false;
+ ValRef ref = target.getOccurrence();
+ if(ref == null || ref.getNext() != null)
+ return false;
+ Object parent = ref.getParent();
+ if(parent instanceof SSAStatement) {
+ if(((SSAStatement)parent).getParent() != getParent())
+ return false;
+ }
+ else if(parent instanceof SSAExit) {
+ if(((SSAExit)parent).getParent() != getParent())
+ return false;
+ if(parent instanceof Switch)
+ return false;
+ }
+ else
+ return false;
+ return true;
+ }
+
+ @Override
+ public void markGenerateOnFly() {
+ target.generateOnFly = determineGenerateOnFly();
+ }
+
+ public ValRef getFunction() {
+ return function;
+ }
+
+ public void setFunction(ValRef function) {
+ this.function = function;
+ function.setParent(this);
+ }
+
+ public ValRef[] getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(ValRef[] parameters) {
+ /*if(SCLCompilerConfiguration.DEBUG)
+ if(parameters.length == 0)
+ throw new InternalCompilerError();*/
+ this.parameters = parameters;
+ for(ValRef parameter : parameters)
+ parameter.setParent(this);
+ }
+
+ @Override
+ public SSAStatement copy(CopyContext context) {
+ LetApply result = new LetApply(context.copy(target),
+ context.copyType(effect),
+ context.copy(function),
+ context.copy(parameters));
+ return result;
+ }
+
+ @Override
+ public void replace(TVar[] vars, Type[] replacements) {
+ target.replace(vars, replacements);
+ function.replace(vars, replacements);
+ effect = effect.replace(vars, replacements);
+ for(ValRef parameter : parameters)
+ parameter.replace(vars, replacements);
+ }
+
+ /**
+ * Inlines the application by the given function.
+ * It is assumed that the function has the same number
+ * of parameters as this one and there are no other
+ * references to the function (copy function before
+ * inlining if necessary).
+ */
+ public void inline(SSAFunction function) {
+ if(function.getArity() != parameters.length)
+ throw new InternalCompilerError();
+
+ SSABlock headBlock = getParent();
+ SSAFunction thisFunction = headBlock.getParent();
+
+ /*System.out.println("--- INLINING -------------------------------");
+ System.out.println(thisFunction);
+ System.out.println("Function name: " + getFunction().getBinding());
+ System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
+ System.out.println(function);
+ */
+
+ if(this.function.getTypeParameters().length > 0) {
+ /*if(function.getParent() != null) {
+ PrintingContext pc = new PrintingContext();
+ pc.append("----------------------------\n");
+ function.getParent().getParentFunction().toString(pc);
+ pc.append("\n----\n");
+ function.toString(pc);
+ pc.append("\n");
+ pc.append(function.getTypeParameters());
+ pc.append(" -> ");
+ pc.append(this.function.getTypeParameters());
+ System.out.println(pc.toString());
+ }*/
+ function.replace(function.getTypeParameters(), this.function.getTypeParameters());
+ }
+
+ if(getPrev() != null)
+ getPrev().setAsLastStatement();
+ else
+ headBlock.removeStatements();
+
+ // Create tail block
+ SSABlock tailBlock = new SSABlock(new BoundVar[] {target});
+ thisFunction.addBlock(tailBlock);
+ {
+ SSAStatement stat = getNext();
+ while(stat != null) {
+ SSAStatement temp = stat.getNext();
+ tailBlock.addStatement(stat);
+ stat = temp;
+ }
+ }
+ tailBlock.setExit(headBlock.getExit());
+
+ // Merge blocks
+ thisFunction.mergeBlocks(function);
+
+ headBlock.setExit(new Jump(function.getFirstBlock().createOccurrence(),
+ parameters));
+ function.getReturnCont().replaceWith(tailBlock);
+
+ this.function.remove();
+ // Note: No need to remove or detach this statement anymore
+
+ // TODO remove function
+ /*
+ System.out.println("============================================");
+ System.out.println(thisFunction);
+ */
+ }
+
+ @Override
+ public void collectFreeVariables(SSAFunction parentFunction,
+ ArrayList<ValRef> vars) {
+ function.collectFreeVariables(parentFunction, vars);
+ for(ValRef parameter : parameters)
+ parameter.collectFreeVariables(parentFunction, vars);
+ }
+
+ @Override
+ public void replaceByApply(ValRef valRef, Val newFunction, Type[] typeParameters, Val[] parameters) {
+ if(function == valRef) {
+ valRef.remove();
+ setFunction(newFunction.createOccurrence(typeParameters));
+ setParameters(ValRef.concat(ValRef.createOccurrences(parameters), this.parameters));
+ }
+ else
+ super.replaceByApply(valRef, newFunction, typeParameters, parameters);
+ }
+
+ /**
+ * Splits this application into two applications where the first has
+ * the arity given as a parameter and the new application inserted
+ * after this statement has the rest of the parameters.
+ */
+ public void split(int arity) {
+ if(arity == parameters.length)
+ return;
+ if(arity > parameters.length)
+ throw new InternalCompilerError();
+ ValRef[] firstHalf = arity == 0 ? ValRef.EMPTY_ARRAY : Arrays.copyOf(parameters, arity);
+ ValRef[] secondHalf = arity == parameters.length ? ValRef.EMPTY_ARRAY : Arrays.copyOfRange(parameters, arity, parameters.length);
+ BoundVar newVar;
+ try {
+ MultiFunction mfun = Types.matchFunction(function.getType(), arity);
+ newVar = new BoundVar(mfun.returnType);
+ } catch (MatchException e) {
+ throw new InternalCompilerError();
+ }
+ LetApply newApply = new LetApply(target, effect,
+ newVar.createOccurrence(), secondHalf);
+ newApply.insertAfter(this);
+ effect = Types.NO_EFFECTS;
+ setTarget(newVar);
+ setParameters(firstHalf);
+ }
+
+ /**
+ * True, if the application may have side effects.
+ */
+ public boolean hasEffect() {
+ return effect != Types.NO_EFFECTS;
+ }
+
+ public void updateEffect() {
+ try {
+ MultiFunction mFun = Types.matchFunction(function.getType(), parameters.length);
+ this.effect = mFun.effect;
+ } catch (MatchException e) {
+ throw new InternalCompilerError(e);
+ }
+ }
+
+ @Override
+ public void prepare(MethodBuilder mb) {
+ function.getBinding().prepare(mb);
+ }
+
+ @Override
+ public void forValRefs(ValRefVisitor visitor) {
+ visitor.visit(function);
+ for(ValRef parameter : parameters)
+ visitor.visit(parameter);
+ }
+
+ @Override
+ public void cleanup() {
+ function.remove();
+ for(ValRef parameter : parameters)
+ parameter.remove();
+ }
+}