import org.cojen.classfile.TypeDesc;
import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.NoRepConstant;
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.internal.codegen.utils.ValRefVisitor;
import org.simantics.scl.compiler.types.TVar;
import org.simantics.scl.compiler.types.Type;
import org.simantics.scl.compiler.types.Types;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class SSAFunction extends SSAClosure {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SSAFunction.class);
-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;
+ ReturnCont returnCont;
public SSAFunction(TVar[] typeParameters, Type effect, Type returnType) {
this(typeParameters, effect, new ReturnCont(returnType));
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;
for(int i=0,j=0;i<firstBlock.parameters.length;++i)
if(!tt.toTypeDesc(firstBlock.parameters[i].getType()).equals(TypeDesc.VOID))
mb.setLocalVariable(firstBlock.parameters[i], mb.getParameter(j++));
+ generateCodeWithAlreadyPreparedParameters(mb);
+ }
+
+ public void generateCodeWithAlreadyPreparedParameters(MethodBuilder mb) {
for(SSABlock block = firstBlock; block != null; block = block.next)
block.prepare(mb);
firstBlock.generateCode(mb);
// Add valid variables and continuations
context.validContinuations.add(returnCont);
- for(SSABlock block = firstBlock; block != null; block = block.next) {
+ for(SSABlock block = firstBlock; block != null; block = block.next) {
context.validContinuations.add(block);
for(BoundVar parameter : block.parameters)
context.validBoundVariables.add(parameter);
//context.reset(); // FIXME not good when there are nested functions
}
- public void simplify(SSASimplificationContext context) {
- /*if(target instanceof BoundVar) {
- tryToMakeMonadic(context);
- }*/
+ @Override
+ public void simplify(SSASimplificationContext 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);
+ if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement) {
+ if(firstBlock.firstStatement instanceof LetApply)
+ simplifySingleApply(context);
+ else if(firstBlock.firstStatement instanceof LetFunctions)
+ simplifySingleLambda(context);
}
}
+
+ /**
+ * Simplifies the following kind of function definition
+ * \x -> f x
+ * to
+ * f
+ */
+ private void simplifySingleApply(SSASimplificationContext context) {
+ if(!(parent instanceof LetFunctions) || parent.getFirstClosure().next != null)
+ return;
+ LetApply apply = (LetApply)firstBlock.firstStatement;
+ if(!(firstBlock.exit instanceof Jump))
+ return;
+ Jump exit = (Jump)firstBlock.exit;
+ if(exit.getTarget().getBinding() != returnCont)
+ return;
+ if(exit.getParameter(0).getBinding() != apply.getTarget())
+ return;
+ BoundVar[] functionParameters = getParameters();
+ ValRef[] applyParameters = apply.getParameters();
+ if(functionParameters.length > applyParameters.length)
+ return;
+ int extraApplyParameters = applyParameters.length - functionParameters.length;
+ for(int i=0;i<functionParameters.length;++i)
+ if(!representSameValues(functionParameters[i], applyParameters[extraApplyParameters+i]))
+ return;
+ for(int i=0;i<extraApplyParameters;++i) {
+ Val b = applyParameters[i].getBinding();
+ if(b instanceof BoundVar) {
+ BoundVar bv = (BoundVar)b;
+ if(bv == target || bv.getParent() == firstBlock)
+ return;
+ }
+ }
+ if(!(target instanceof BoundVar))
+ return;
+
+ // Transform
+
+ LetFunctions binder = (LetFunctions)parent;
+ SSAFunction parentFunction = binder.getParentFunction();
+ if(extraApplyParameters > 0) {
+ //System.out.println("-------------------------------------------------------------");
+ //System.out.println(parentFunction);
+ //System.out.println("-------------------------------------------------------------");
+ apply.setTarget((BoundVar)target);
+ apply.setParameters(Arrays.copyOf(applyParameters, extraApplyParameters));
+ apply.insertBefore(binder);
+ binder.detach();
+ //System.out.println(parentFunction);
+ //System.out.println("-------------------------------------------------------------");
+ }
+ else {
+ binder.detach();
+ ((BoundVar)target).replaceBy(apply.getFunction());
+ }
+ context.markModified("SSAFunction.eta-reduce");
+ }
+
+ private boolean representSameValues(BoundVar boundVar, ValRef valRef) {
+ Val val = valRef.getBinding();
+ if(val == boundVar && valRef.getTypeParameters().length == 0)
+ return true;
+ if(val instanceof NoRepConstant && Types.equals(valRef.getType(), boundVar.getType()))
+ return true;
+ return false;
+ }
+
+ /**
+ * Simplifies the following kind of function definition
+ * \x -> \y -> e
+ * to
+ * \x y -> e
+ */
private void simplifySingleLambda(SSASimplificationContext context) {
LetFunctions letF = (LetFunctions)firstBlock.firstStatement;
- SSAFunction f = letF.getFirstFunction();
+ if(!(letF.getFirstClosure() instanceof SSAFunction))
+ return;
+ SSAFunction f = (SSAFunction)letF.getFirstClosure();
if(f.getNext() != null)
return;
Val fVal = f.getTarget();
for(SSABlock block = f.firstBlock; block != null; block = block.next)
block.parent = this;
lastBlock.next = f.firstBlock;
- f.firstBlock.prev = lastBlock;
+ f.firstBlock.prev = lastBlock;
lastBlock = f.lastBlock;
firstBlock.firstStatement = firstBlock.lastStatement = null;
- setReturnCont(f.getReturnCont());
+ 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)));
+ firstBlock.setExit(new Jump(-1, f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters)));
context.markModified("SSAFunction.simplify-simple-lambda");
}
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 firstBlock.parameters.length;
}
+ @Override
public void markGenerateOnFly() {
for(SSABlock block = firstBlock; block != null; block = block.next)
block.markGenerateOnFly();
}
- public SSAFunction copy(CopyContext context) {
+ @Override
+ public SSAClosure copy(CopyContext context) {
TVar[] newTypeParameters = context.copyParameters(typeParameters);
SSAFunction newFunction = new SSAFunction(newTypeParameters, effect, context.copy(returnCont));
for(SSABlock block = firstBlock;
newFunction.addBlock(context.copy(block));
return newFunction;
}
-
- public SSAFunction copy() {
- return copy(new CopyContext());
- }
-
+
+ @Override
public void replace(TVar[] vars, Type[] replacements) {
returnCont.replace(vars, replacements);
for(SSABlock block = firstBlock;
this.typeParameters = typeParameters;
}
+ @Override
public Type getType() {
Type type = returnCont.getType();
type = Types.functionE(
}
public void mergeBlocks(SSAFunction function) {
+ if(this == function)
+ throw new InternalCompilerError();
SSABlock block = function.firstBlock;
while(block != null) {
SSABlock next = block.next;
return returnCont.getType();
}
+ @Override
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;
- }
-
+ @Override
public void collectFreeVariables(ArrayList<ValRef> 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;
- }
+ @Override
public void lambdaLift(SSALambdaLiftingContext context) {
for(SSABlock block = firstBlock;
block != null; block = block.next)
block.lambdaLift(context);
}
- public void addParametersInFront(BoundVar[] parameters) {
+ @Override
+ public void parametrize(BoundVar[] parameters) {
Cont proxy = null;
for(ContRef ref = firstBlock.getOccurrence(); ref != null; ref = ref.getNext())
proxy = ref.addParametersInFront(parameters, firstBlock.parameters, proxy);
parameter.parent = firstBlock;
}
- public void apply(ValRef[] parameters) {
+ public void apply(int lineNumber, ValRef[] parameters) {
if(parameters.length == 0)
return;
if(firstBlock.hasNoOccurences()) {
else {
BoundVar[] newVars = new BoundVar[getArity()-parameters.length];
SSABlock block = new SSABlock(newVars);
- block.setExit(new Jump(firstBlock.createOccurrence(),
+ block.setExit(new Jump(lineNumber, firstBlock.createOccurrence(),
ValRef.concat(ValRef.copy(parameters), ValRef.createOccurrences(newVars))));
addBlockInFront(block);
}
return effect;
}
- public int getBlockCount() {
- int count = 0;
- for(SSABlock block = firstBlock;block != null;block = block.next)
- ++count;
- return count;
+ @Override
+ public boolean isValue() {
+ return getArity() == 0;
}
+ @Override
+ public void forValRefs(ValRefVisitor visitor) {
+ for(SSABlock block = firstBlock;
+ block != null; block = block.next)
+ block.forValRefs(visitor);
+ }
+
+ @Override
+ public void cleanup() {
+ for(SSABlock block = firstBlock; block != null; block = block.next)
+ block.cleanup();
+ }
}