1 package org.simantics.scl.compiler.internal.codegen.ssa;
3 import java.util.ArrayList;
4 import java.util.Arrays;
6 import org.cojen.classfile.TypeDesc;
7 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
8 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
9 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
10 import org.simantics.scl.compiler.internal.codegen.continuations.ReturnCont;
11 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
12 import org.simantics.scl.compiler.internal.codegen.references.Val;
13 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
14 import org.simantics.scl.compiler.internal.codegen.ssa.binders.BoundVarBinder;
15 import org.simantics.scl.compiler.internal.codegen.ssa.binders.FunctionBinder;
16 import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;
17 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
18 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions;
19 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
20 import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
21 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
22 import org.simantics.scl.compiler.internal.codegen.utils.Printable;
23 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
24 import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
25 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
26 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
27 import org.simantics.scl.compiler.types.TVar;
28 import org.simantics.scl.compiler.types.Type;
29 import org.simantics.scl.compiler.types.Types;
31 public final class SSAFunction implements Printable, BoundVarBinder {
34 TVar[] typeParameters;
38 ReturnCont returnCont;
40 FunctionBinder parent;
44 public SSAFunction(TVar[] typeParameters, Type effect, Type returnType) {
45 this(typeParameters, effect, new ReturnCont(returnType));
48 public SSAFunction(TVar[] typeParameters, Type effect, ReturnCont returnCont) {
49 this.typeParameters = typeParameters;
50 this.returnCont = returnCont;
51 this.effect = Types.canonical(effect);
52 returnCont.setParent(this);
55 public Val getTarget() {
59 public void setTarget(Val target) {
61 if(target instanceof BoundVar)
62 ((BoundVar) target).parent = this;
65 public void setTarget(BoundVar target) {
70 public boolean hasEffect() {
71 return effect != Types.NO_EFFECTS;
74 public void addBlock(SSABlock block) {
76 if(lastBlock == null) {
77 firstBlock = lastBlock = block;
78 block.next = block.prev = null;
81 lastBlock.next = block;
82 block.prev = lastBlock;
88 public void addBlockInFront(SSABlock block) {
90 if(firstBlock == null) {
91 firstBlock = lastBlock = block;
92 block.next = block.prev = null;
95 firstBlock.prev = block;
96 block.next = firstBlock;
102 public ReturnCont getReturnCont() {
106 public TVar[] getTypeParameters() {
107 return typeParameters;
110 public SSABlock getFirstBlock() {
114 public void generateCode(MethodBuilder mb) {
115 JavaTypeTranslator tt = mb.getJavaTypeTranslator();
116 for(int i=0,j=0;i<firstBlock.parameters.length;++i)
117 if(!tt.toTypeDesc(firstBlock.parameters[i].getType()).equals(TypeDesc.VOID))
118 mb.setLocalVariable(firstBlock.parameters[i], mb.getParameter(j++));
119 for(SSABlock block = firstBlock; block != null; block = block.next)
121 firstBlock.generateCode(mb);
124 public void toString(PrintingContext context) {
125 context.indentation();
126 if(typeParameters.length > 0) {
128 boolean first = true;
129 for(TVar var : typeParameters) {
136 context.append("> ");
139 context.append(effect);
142 context.append("RETURNS ");
143 context.append(returnCont.getType());
144 context.append('\n');
147 context.pushBlockQueue();
148 context.addBlock(getFirstBlock());
150 SSABlock block = context.pollBlock();
153 block.toString(context);
155 context.popBlockQueue();
159 public String toString() {
160 PrintingContext context = new PrintingContext();
162 return context.toString();
165 public void validate(SSAValidationContext context) {
166 if(target instanceof BoundVar && ((BoundVar)target).parent != this)
167 throw new InternalCompilerError();
169 // Add valid type variables
170 for(TVar var : typeParameters)
171 context.validTypeVariables.add(var);
173 // Add valid variables and continuations
174 context.validContinuations.add(returnCont);
175 for(SSABlock block = firstBlock; block != null; block = block.next) {
176 context.validContinuations.add(block);
177 for(BoundVar parameter : block.parameters)
178 context.validBoundVariables.add(parameter);
179 for(SSAStatement stat = block.firstStatement; stat != null; stat = stat.next)
180 stat.addBoundVariablesTo(context);
184 for(SSABlock block = firstBlock; block != null; block = block.next)
185 block.validate(context);
186 context.validate(returnCont);
188 //context.reset(); // FIXME not good when there are nested functions
191 public void simplify(SSASimplificationContext context) {
192 /*if(target instanceof BoundVar) {
193 tryToMakeMonadic(context);
195 for(SSABlock block = firstBlock; block != null; block = block.next)
196 block.simplify(context);
197 if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement &&
198 firstBlock.firstStatement instanceof LetFunctions) {
199 simplifySingleLambda(context);
203 private void simplifySingleLambda(SSASimplificationContext context) {
204 LetFunctions letF = (LetFunctions)firstBlock.firstStatement;
205 SSAFunction f = letF.getFirstFunction();
206 if(f.getNext() != null)
208 Val fVal = f.getTarget();
209 if(!firstBlock.exit.isJump(getReturnCont(), fVal))
211 if(fVal.hasMoreThanOneOccurences())
212 return; // Possible if function is recursive and refers to itself
214 return; // Not probably possible (?)
217 for(SSABlock block = f.firstBlock; block != null; block = block.next)
219 lastBlock.next = f.firstBlock;
220 f.firstBlock.prev = lastBlock;
221 lastBlock = f.lastBlock;
223 firstBlock.firstStatement = firstBlock.lastStatement = null;
224 setReturnCont(f.getReturnCont());
226 BoundVar[] newParameters = BoundVar.copy(f.firstBlock.parameters);
227 firstBlock.setParameters(BoundVar.concat(getParameters(), newParameters));
228 firstBlock.setExit(new Jump(f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters)));
229 context.markModified("SSAFunction.simplify-simple-lambda");
232 public void setReturnCont(ReturnCont returnCont) {
233 this.returnCont = returnCont;
234 returnCont.setParent(this);
237 /*public void tryToMakeMonadic(SSASimplificationContext context) {
240 if(!Types.isApply(BTypes.PROC, 1, getReturnType()))
242 for(ValRef ref = target.getOccurrence(); ref != null; ref = ref.getNext()) {
243 ValRefBinder parent = ref.getParent();
244 if(!(parent instanceof LetApply))
246 LetApply apply = (LetApply)parent;
247 if(apply.getFunction() != ref)
249 if(apply.getParameters().length != getParameters().length)
251 if(!apply.hasEffect())
254 makeMonadic(context);
257 /*private void makeMonadic(SSASimplificationContext context) {
258 Type oldReturnType = returnCont.getType();
261 newReturnType = Types.matchApply(BTypes.PROC, oldReturnType);
262 } catch (MatchException e) {
263 throw new InternalCompilerError();
267 returnCont.setType(newReturnType);
271 SSABlock block = new SSABlock(oldReturnType);
274 returnCont.replaceWith(block);
276 BoundVar x = new BoundVar(newReturnType);
277 LetApply apply = new LetApply(x, block.parameters[0].createOccurrence());
278 apply.setMonadic(true);
279 block.addStatement(apply);
281 block.setExit(new Jump(returnCont.createOccurrence(), x.createOccurrence()));
282 context.markModified("SSAFunction.make-monadic");
285 public ValRef isEqualToConstant() {
286 if(firstBlock.parameters.length > 0)
288 if(firstBlock != lastBlock)
290 if(firstBlock.firstStatement != null)
292 if(!(firstBlock.exit instanceof Jump))
294 Jump exit = (Jump)firstBlock.exit;
295 if(exit.getTarget().getBinding() != returnCont)
297 return exit.getParameters()[0];
300 public BoundVar[] getParameters() {
301 return firstBlock.parameters;
304 public Type[] getParameterTypes() {
305 return Types.getTypes(firstBlock.parameters);
308 public int getArity() {
309 return firstBlock.parameters.length;
312 public void markGenerateOnFly() {
313 for(SSABlock block = firstBlock; block != null; block = block.next)
314 block.markGenerateOnFly();
317 public SSAFunction copy(CopyContext context) {
318 TVar[] newTypeParameters = context.copyParameters(typeParameters);
319 SSAFunction newFunction = new SSAFunction(newTypeParameters, effect, context.copy(returnCont));
320 for(SSABlock block = firstBlock;
321 block != null; block = block.next)
322 newFunction.addBlock(context.copy(block));
326 public SSAFunction copy() {
327 return copy(new CopyContext());
330 public void replace(TVar[] vars, Type[] replacements) {
331 returnCont.replace(vars, replacements);
332 for(SSABlock block = firstBlock;
333 block != null; block = block.next)
334 block.replace(vars, replacements);
337 public void setTypeParameters(TVar[] typeParameters) {
338 this.typeParameters = typeParameters;
341 public Type getType() {
342 Type type = returnCont.getType();
343 type = Types.functionE(
344 Types.getTypes(firstBlock.parameters),
347 type = Types.forAll(typeParameters, type);
351 public void mergeBlocks(SSAFunction function) {
352 SSABlock block = function.firstBlock;
353 while(block != null) {
354 SSABlock next = block.next;
360 public Type getReturnType() {
361 return returnCont.getType();
364 public void destroy() {
365 for(SSABlock block = firstBlock;
366 block != null; block = block.next)
370 public void detach() {
372 parent.setFirstFunction(next);
379 public void remove() {
384 public void addSibling(SSAFunction function) {
385 function.parent = parent;
386 function.next = next;
387 function.prev = this;
389 next.prev = function;
393 public SSAFunction getNext() {
397 public void setParent(FunctionBinder parent) {
398 this.parent = parent;
401 public void setPrev(SSAFunction function) {
402 this.prev = function;
405 public void setNext(SSAFunction function) {
406 this.next = function;
409 public void collectFreeVariables(ArrayList<ValRef> vars) {
410 for(SSABlock block = firstBlock;
411 block != null; block = block.next)
412 block.collectFreeVariables(this, vars);
416 public SSAFunction getParentFunction() {
417 return parent.getParentFunction();
420 public FunctionBinder getParent() {
424 public void lambdaLift(SSALambdaLiftingContext context) {
425 for(SSABlock block = firstBlock;
426 block != null; block = block.next)
427 block.lambdaLift(context);
430 public void addParametersInFront(BoundVar[] parameters) {
432 for(ContRef ref = firstBlock.getOccurrence(); ref != null; ref = ref.getNext())
433 proxy = ref.addParametersInFront(parameters, firstBlock.parameters, proxy);
435 firstBlock.parameters = BoundVar.concat(parameters, firstBlock.parameters);
436 for(BoundVar parameter : parameters)
437 parameter.parent = firstBlock;
440 public void apply(ValRef[] parameters) {
441 if(parameters.length == 0)
443 if(firstBlock.hasNoOccurences()) {
444 BoundVar[] vars = firstBlock.getParameters();
445 for(int i=0;i<parameters.length;++i)
446 vars[i].replaceBy(parameters[i]);
447 firstBlock.setParameters(Arrays.copyOfRange(vars, parameters.length, vars.length));
450 BoundVar[] newVars = new BoundVar[getArity()-parameters.length];
451 SSABlock block = new SSABlock(newVars);
452 block.setExit(new Jump(firstBlock.createOccurrence(),
453 ValRef.concat(ValRef.copy(parameters), ValRef.createOccurrences(newVars))));
454 addBlockInFront(block);
458 public void applyTypes(Type[] types) {
459 if(types.length == 0)
461 if(types.length == typeParameters.length) {
462 replace(typeParameters, types);
463 typeParameters = TVar.EMPTY_ARRAY;
466 replace(Arrays.copyOf(typeParameters, types.length), types);
468 Arrays.copyOfRange(typeParameters,
469 types.length, typeParameters.length);
473 public boolean isSimpleEnoughForInline() {
474 return firstBlock == lastBlock &&
475 (firstBlock.firstStatement == null ||
476 (firstBlock.firstStatement == firstBlock.lastStatement
477 && firstBlock.firstStatement instanceof LetApply));
480 public Type getEffect() {
484 public int getBlockCount() {
486 for(SSABlock block = firstBlock;block != null;block = block.next)