package org.simantics.scl.compiler.internal.codegen.ssa; import java.util.ArrayList; import java.util.Arrays; import org.cojen.classfile.TypeDesc; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.internal.codegen.continuations.Cont; import org.simantics.scl.compiler.internal.codegen.continuations.ContRef; import org.simantics.scl.compiler.internal.codegen.continuations.ReturnCont; 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.binders.BoundVarBinder; import org.simantics.scl.compiler.internal.codegen.ssa.binders.FunctionBinder; 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.types.JavaTypeTranslator; 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.Printable; import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext; import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext; import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext; import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; public final class SSAFunction implements Printable, BoundVarBinder { Val target; TVar[] typeParameters; Type effect; SSABlock firstBlock; SSABlock lastBlock; ReturnCont returnCont; FunctionBinder parent; SSAFunction prev; SSAFunction next; public SSAFunction(TVar[] typeParameters, Type effect, Type returnType) { this(typeParameters, effect, new ReturnCont(returnType)); } public SSAFunction(TVar[] typeParameters, Type effect, ReturnCont returnCont) { this.typeParameters = typeParameters; this.returnCont = returnCont; this.effect = Types.canonical(effect); returnCont.setParent(this); } public Val getTarget() { return target; } public void setTarget(Val target) { this.target = target; if(target instanceof BoundVar) ((BoundVar) target).parent = this; } public void setTarget(BoundVar target) { this.target = target; target.parent = this; } public boolean hasEffect() { return effect != Types.NO_EFFECTS; } public void addBlock(SSABlock block) { block.parent = this; if(lastBlock == null) { firstBlock = lastBlock = block; block.next = block.prev = null; } else { lastBlock.next = block; block.prev = lastBlock; block.next = null; lastBlock = block; } } public void addBlockInFront(SSABlock block) { block.parent = this; if(firstBlock == null) { firstBlock = lastBlock = block; block.next = block.prev = null; } else { firstBlock.prev = block; block.next = firstBlock; block.prev = null; firstBlock = block; } } public ReturnCont getReturnCont() { return returnCont; } public TVar[] getTypeParameters() { return typeParameters; } public SSABlock getFirstBlock() { return firstBlock; } public void generateCode(MethodBuilder mb) { JavaTypeTranslator tt = mb.getJavaTypeTranslator(); for(int i=0,j=0;i 0) { context.append('<'); boolean first = true; for(TVar var : typeParameters) { if(first) first = false; else context.append(','); context.append(var); } context.append("> "); } if(hasEffect()) { context.append(effect); context.append(" "); } context.append("RETURNS "); context.append(returnCont.getType()); context.append('\n'); // Print blocks context.pushBlockQueue(); context.addBlock(getFirstBlock()); while(true) { SSABlock block = context.pollBlock(); if(block == null) break; block.toString(context); } context.popBlockQueue(); } @Override public String toString() { PrintingContext context = new PrintingContext(); toString(context); return context.toString(); } public void validate(SSAValidationContext context) { if(target instanceof BoundVar && ((BoundVar)target).parent != this) throw new InternalCompilerError(); // Add valid type variables for(TVar var : typeParameters) context.validTypeVariables.add(var); // Add valid variables and continuations context.validContinuations.add(returnCont); for(SSABlock block = firstBlock; block != null; block = block.next) { context.validContinuations.add(block); for(BoundVar parameter : block.parameters) context.validBoundVariables.add(parameter); for(SSAStatement stat = block.firstStatement; stat != null; stat = stat.next) stat.addBoundVariablesTo(context); } // Validate blocks for(SSABlock block = firstBlock; block != null; block = block.next) block.validate(context); context.validate(returnCont); //context.reset(); // FIXME not good when there are nested functions } public void simplify(SSASimplificationContext context) { /*if(target instanceof BoundVar) { tryToMakeMonadic(context); }*/ for(SSABlock block = firstBlock; block != null; block = block.next) block.simplify(context); if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement && firstBlock.firstStatement instanceof LetFunctions) { simplifySingleLambda(context); } } private void simplifySingleLambda(SSASimplificationContext context) { LetFunctions letF = (LetFunctions)firstBlock.firstStatement; SSAFunction f = letF.getFirstFunction(); if(f.getNext() != null) return; Val fVal = f.getTarget(); if(!firstBlock.exit.isJump(getReturnCont(), fVal)) return; if(fVal.hasMoreThanOneOccurences()) return; // Possible if function is recursive and refers to itself if(hasEffect()) return; // Not probably possible (?) // Transform for(SSABlock block = f.firstBlock; block != null; block = block.next) block.parent = this; lastBlock.next = f.firstBlock; f.firstBlock.prev = lastBlock; lastBlock = f.lastBlock; firstBlock.firstStatement = firstBlock.lastStatement = null; setReturnCont(f.getReturnCont()); effect = f.effect; BoundVar[] newParameters = BoundVar.copy(f.firstBlock.parameters); firstBlock.setParameters(BoundVar.concat(getParameters(), newParameters)); firstBlock.setExit(new Jump(f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters))); context.markModified("SSAFunction.simplify-simple-lambda"); } public void setReturnCont(ReturnCont returnCont) { this.returnCont = returnCont; returnCont.setParent(this); } /*public void tryToMakeMonadic(SSASimplificationContext context) { if(monadic) return; if(!Types.isApply(BTypes.PROC, 1, getReturnType())) return; for(ValRef ref = target.getOccurrence(); ref != null; ref = ref.getNext()) { ValRefBinder parent = ref.getParent(); if(!(parent instanceof LetApply)) return; LetApply apply = (LetApply)parent; if(apply.getFunction() != ref) return; if(apply.getParameters().length != getParameters().length) return; if(!apply.hasEffect()) return; } makeMonadic(context); }*/ /*private void makeMonadic(SSASimplificationContext context) { Type oldReturnType = returnCont.getType(); Type newReturnType; try { newReturnType = Types.matchApply(BTypes.PROC, oldReturnType); } catch (MatchException e) { throw new InternalCompilerError(); } // returnCont.setType(newReturnType); monadic = true; // SSABlock block = new SSABlock(oldReturnType); addBlock(block); returnCont.replaceWith(block); BoundVar x = new BoundVar(newReturnType); LetApply apply = new LetApply(x, block.parameters[0].createOccurrence()); apply.setMonadic(true); block.addStatement(apply); block.setExit(new Jump(returnCont.createOccurrence(), x.createOccurrence())); context.markModified("SSAFunction.make-monadic"); }*/ public ValRef isEqualToConstant() { if(firstBlock.parameters.length > 0) return null; if(firstBlock != lastBlock) return null; if(firstBlock.firstStatement != null) return null; if(!(firstBlock.exit instanceof Jump)) return null; Jump exit = (Jump)firstBlock.exit; if(exit.getTarget().getBinding() != returnCont) return null; return exit.getParameters()[0]; } public BoundVar[] getParameters() { return firstBlock.parameters; } public Type[] getParameterTypes() { return Types.getTypes(firstBlock.parameters); } public int getArity() { return firstBlock.parameters.length; } public void markGenerateOnFly() { for(SSABlock block = firstBlock; block != null; block = block.next) block.markGenerateOnFly(); } public SSAFunction copy(CopyContext context) { TVar[] newTypeParameters = context.copyParameters(typeParameters); SSAFunction newFunction = new SSAFunction(newTypeParameters, effect, context.copy(returnCont)); for(SSABlock block = firstBlock; block != null; block = block.next) newFunction.addBlock(context.copy(block)); return newFunction; } public SSAFunction copy() { return copy(new CopyContext()); } public void replace(TVar[] vars, Type[] replacements) { returnCont.replace(vars, replacements); for(SSABlock block = firstBlock; block != null; block = block.next) block.replace(vars, replacements); } public void setTypeParameters(TVar[] typeParameters) { this.typeParameters = typeParameters; } public Type getType() { Type type = returnCont.getType(); type = Types.functionE( Types.getTypes(firstBlock.parameters), effect, type); type = Types.forAll(typeParameters, type); return type; } public void mergeBlocks(SSAFunction function) { SSABlock block = function.firstBlock; while(block != null) { SSABlock next = block.next; addBlock(block); block = next; } } public Type getReturnType() { return returnCont.getType(); } public void destroy() { for(SSABlock block = firstBlock; block != null; block = block.next) block.destroy(); } public void detach() { if(prev == null) parent.setFirstFunction(next); else prev.next = next; if(next != null) next.prev = prev; } public void remove() { destroy(); detach(); } public void addSibling(SSAFunction function) { function.parent = parent; function.next = next; function.prev = this; next.prev = function; next = function; } public SSAFunction getNext() { return next; } public void setParent(FunctionBinder parent) { this.parent = parent; } public void setPrev(SSAFunction function) { this.prev = function; } public void setNext(SSAFunction function) { this.next = function; } public void collectFreeVariables(ArrayList vars) { for(SSABlock block = firstBlock; block != null; block = block.next) block.collectFreeVariables(this, vars); } @Override public SSAFunction getParentFunction() { return parent.getParentFunction(); } public FunctionBinder getParent() { return parent; } public void lambdaLift(SSALambdaLiftingContext context) { for(SSABlock block = firstBlock; block != null; block = block.next) block.lambdaLift(context); } public void addParametersInFront(BoundVar[] parameters) { Cont proxy = null; for(ContRef ref = firstBlock.getOccurrence(); ref != null; ref = ref.getNext()) proxy = ref.addParametersInFront(parameters, firstBlock.parameters, proxy); firstBlock.parameters = BoundVar.concat(parameters, firstBlock.parameters); for(BoundVar parameter : parameters) parameter.parent = firstBlock; } public void apply(ValRef[] parameters) { if(parameters.length == 0) return; if(firstBlock.hasNoOccurences()) { BoundVar[] vars = firstBlock.getParameters(); for(int i=0;i