X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Finternal%2Fcodegen%2Fssa%2Fstatements%2FLetApply.java;h=400cb6e4e373f78c480e8fc37c1da3dc203a47f2;hp=83b1e0cb67a81afe13249ace83f230097b2ed892;hb=fad36d463b75c3a9944d875fc627c3533f6da74d;hpb=3303fe4a3b363e88662ac75a4f7e873ddb3ab352 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java index 83b1e0cb6..400cb6e4e 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetApply.java @@ -1,462 +1,491 @@ -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.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.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(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 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 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 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); - } -} +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 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 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 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); + } +}