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.constants.NoRepConstant;
9 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
10 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
11 import org.simantics.scl.compiler.internal.codegen.continuations.ReturnCont;
12 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
13 import org.simantics.scl.compiler.internal.codegen.references.Val;
14 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
15 import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump;
16 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
17 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions;
18 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
19 import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
20 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
21 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
22 import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
23 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
24 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
25 import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
26 import org.simantics.scl.compiler.types.TVar;
27 import org.simantics.scl.compiler.types.Type;
28 import org.simantics.scl.compiler.types.Types;
30 public final class SSAFunction extends SSAClosure {
31 TVar[] typeParameters;
35 ReturnCont returnCont;
37 public SSAFunction(TVar[] typeParameters, Type effect, Type returnType) {
38 this(typeParameters, effect, new ReturnCont(returnType));
41 public SSAFunction(TVar[] typeParameters, Type effect, ReturnCont returnCont) {
42 this.typeParameters = typeParameters;
43 this.returnCont = returnCont;
44 this.effect = Types.canonical(effect);
45 returnCont.setParent(this);
48 public boolean hasEffect() {
49 return effect != Types.NO_EFFECTS;
52 public void addBlock(SSABlock block) {
54 if(lastBlock == null) {
55 firstBlock = lastBlock = block;
56 block.next = block.prev = null;
59 lastBlock.next = block;
60 block.prev = lastBlock;
66 public void addBlockInFront(SSABlock block) {
68 if(firstBlock == null) {
69 firstBlock = lastBlock = block;
70 block.next = block.prev = null;
73 firstBlock.prev = block;
74 block.next = firstBlock;
80 public ReturnCont getReturnCont() {
84 public TVar[] getTypeParameters() {
85 return typeParameters;
88 public SSABlock getFirstBlock() {
92 public void generateCode(MethodBuilder mb) {
93 JavaTypeTranslator tt = mb.getJavaTypeTranslator();
94 for(int i=0,j=0;i<firstBlock.parameters.length;++i)
95 if(!tt.toTypeDesc(firstBlock.parameters[i].getType()).equals(TypeDesc.VOID))
96 mb.setLocalVariable(firstBlock.parameters[i], mb.getParameter(j++));
97 generateCodeWithAlreadyPreparedParameters(mb);
100 public void generateCodeWithAlreadyPreparedParameters(MethodBuilder mb) {
101 for(SSABlock block = firstBlock; block != null; block = block.next)
103 firstBlock.generateCode(mb);
106 public void toString(PrintingContext context) {
107 context.indentation();
108 if(typeParameters.length > 0) {
110 boolean first = true;
111 for(TVar var : typeParameters) {
118 context.append("> ");
121 context.append(effect);
124 context.append("RETURNS ");
125 context.append(returnCont.getType());
126 context.append('\n');
129 context.pushBlockQueue();
130 context.addBlock(getFirstBlock());
132 SSABlock block = context.pollBlock();
135 block.toString(context);
137 context.popBlockQueue();
141 public String toString() {
142 PrintingContext context = new PrintingContext();
144 return context.toString();
147 public void validate(SSAValidationContext context) {
148 if(target instanceof BoundVar && ((BoundVar)target).parent != this)
149 throw new InternalCompilerError();
151 // Add valid type variables
152 for(TVar var : typeParameters)
153 context.validTypeVariables.add(var);
155 // Add valid variables and continuations
156 context.validContinuations.add(returnCont);
157 for(SSABlock block = firstBlock; block != null; block = block.next) {
158 context.validContinuations.add(block);
159 for(BoundVar parameter : block.parameters)
160 context.validBoundVariables.add(parameter);
161 for(SSAStatement stat = block.firstStatement; stat != null; stat = stat.next)
162 stat.addBoundVariablesTo(context);
166 for(SSABlock block = firstBlock; block != null; block = block.next)
167 block.validate(context);
168 context.validate(returnCont);
170 //context.reset(); // FIXME not good when there are nested functions
174 public void simplify(SSASimplificationContext context) {
175 for(SSABlock block = firstBlock; block != null; block = block.next)
176 block.simplify(context);
177 if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement) {
178 if(firstBlock.firstStatement instanceof LetApply)
179 simplifySingleApply(context);
180 else if(firstBlock.firstStatement instanceof LetFunctions)
181 simplifySingleLambda(context);
187 * Simplifies the following kind of function definition
192 private void simplifySingleApply(SSASimplificationContext context) {
193 if(!(parent instanceof LetFunctions) || parent.getFirstClosure().next != null)
195 LetApply apply = (LetApply)firstBlock.firstStatement;
196 if(!(firstBlock.exit instanceof Jump))
198 Jump exit = (Jump)firstBlock.exit;
199 if(exit.getTarget().getBinding() != returnCont)
201 if(exit.getParameter(0).getBinding() != apply.getTarget())
203 BoundVar[] functionParameters = getParameters();
204 ValRef[] applyParameters = apply.getParameters();
205 if(functionParameters.length > applyParameters.length)
207 int extraApplyParameters = applyParameters.length - functionParameters.length;
208 for(int i=0;i<functionParameters.length;++i)
209 if(!representSameValues(functionParameters[i], applyParameters[extraApplyParameters+i]))
211 for(int i=0;i<extraApplyParameters;++i) {
212 Val b = applyParameters[i].getBinding();
213 if(b instanceof BoundVar) {
214 BoundVar bv = (BoundVar)b;
215 if(bv == target || bv.getParent() == firstBlock)
219 if(!(target instanceof BoundVar))
224 LetFunctions binder = (LetFunctions)parent;
225 SSAFunction parentFunction = binder.getParentFunction();
226 if(extraApplyParameters > 0) {
227 //System.out.println("-------------------------------------------------------------");
228 //System.out.println(parentFunction);
229 //System.out.println("-------------------------------------------------------------");
230 apply.setTarget((BoundVar)target);
231 apply.setParameters(Arrays.copyOf(applyParameters, extraApplyParameters));
232 apply.insertBefore(binder);
234 //System.out.println(parentFunction);
235 //System.out.println("-------------------------------------------------------------");
239 ((BoundVar)target).replaceBy(apply.getFunction());
241 context.markModified("SSAFunction.eta-reduce");
244 private boolean representSameValues(BoundVar boundVar, ValRef valRef) {
245 Val val = valRef.getBinding();
246 if(val == boundVar && valRef.getTypeParameters().length == 0)
248 if(val instanceof NoRepConstant && Types.equals(valRef.getType(), boundVar.getType()))
254 * Simplifies the following kind of function definition
259 private void simplifySingleLambda(SSASimplificationContext context) {
260 LetFunctions letF = (LetFunctions)firstBlock.firstStatement;
261 if(!(letF.getFirstClosure() instanceof SSAFunction))
263 SSAFunction f = (SSAFunction)letF.getFirstClosure();
264 if(f.getNext() != null)
266 Val fVal = f.getTarget();
267 if(!firstBlock.exit.isJump(getReturnCont(), fVal))
269 if(fVal.hasMoreThanOneOccurences())
270 return; // Possible if function is recursive and refers to itself
272 return; // Not probably possible (?)
275 for(SSABlock block = f.firstBlock; block != null; block = block.next)
277 lastBlock.next = f.firstBlock;
278 f.firstBlock.prev = lastBlock;
279 lastBlock = f.lastBlock;
281 firstBlock.firstStatement = firstBlock.lastStatement = null;
282 setReturnCont(f.getReturnCont());
284 BoundVar[] newParameters = BoundVar.copy(f.firstBlock.parameters);
285 firstBlock.setParameters(BoundVar.concat(getParameters(), newParameters));
286 firstBlock.setExit(new Jump(f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters)));
287 context.markModified("SSAFunction.simplify-simple-lambda");
290 public void setReturnCont(ReturnCont returnCont) {
291 this.returnCont = returnCont;
292 returnCont.setParent(this);
295 public ValRef isEqualToConstant() {
296 if(firstBlock.parameters.length > 0)
298 if(firstBlock != lastBlock)
300 if(firstBlock.firstStatement != null)
302 if(!(firstBlock.exit instanceof Jump))
304 Jump exit = (Jump)firstBlock.exit;
305 if(exit.getTarget().getBinding() != returnCont)
307 return exit.getParameters()[0];
310 public BoundVar[] getParameters() {
311 return firstBlock.parameters;
314 public Type[] getParameterTypes() {
315 return Types.getTypes(firstBlock.parameters);
318 public int getArity() {
319 return firstBlock.parameters.length;
323 public void markGenerateOnFly() {
324 for(SSABlock block = firstBlock; block != null; block = block.next)
325 block.markGenerateOnFly();
329 public SSAClosure copy(CopyContext context) {
330 TVar[] newTypeParameters = context.copyParameters(typeParameters);
331 SSAFunction newFunction = new SSAFunction(newTypeParameters, effect, context.copy(returnCont));
332 for(SSABlock block = firstBlock;
333 block != null; block = block.next)
334 newFunction.addBlock(context.copy(block));
339 public void replace(TVar[] vars, Type[] replacements) {
340 returnCont.replace(vars, replacements);
341 for(SSABlock block = firstBlock;
342 block != null; block = block.next)
343 block.replace(vars, replacements);
346 public void setTypeParameters(TVar[] typeParameters) {
347 this.typeParameters = typeParameters;
351 public Type getType() {
352 Type type = returnCont.getType();
353 type = Types.functionE(
354 Types.getTypes(firstBlock.parameters),
357 type = Types.forAll(typeParameters, type);
361 public void mergeBlocks(SSAFunction function) {
363 throw new InternalCompilerError();
364 SSABlock block = function.firstBlock;
365 while(block != null) {
366 SSABlock next = block.next;
372 public Type getReturnType() {
373 return returnCont.getType();
377 public void destroy() {
378 for(SSABlock block = firstBlock;
379 block != null; block = block.next)
384 public void collectFreeVariables(ArrayList<ValRef> vars) {
385 for(SSABlock block = firstBlock;
386 block != null; block = block.next)
387 block.collectFreeVariables(this, vars);
391 public void lambdaLift(SSALambdaLiftingContext context) {
392 for(SSABlock block = firstBlock;
393 block != null; block = block.next)
394 block.lambdaLift(context);
398 public void parametrize(BoundVar[] parameters) {
400 for(ContRef ref = firstBlock.getOccurrence(); ref != null; ref = ref.getNext())
401 proxy = ref.addParametersInFront(parameters, firstBlock.parameters, proxy);
403 firstBlock.parameters = BoundVar.concat(parameters, firstBlock.parameters);
404 for(BoundVar parameter : parameters)
405 parameter.parent = firstBlock;
408 public void apply(ValRef[] parameters) {
409 if(parameters.length == 0)
411 if(firstBlock.hasNoOccurences()) {
412 BoundVar[] vars = firstBlock.getParameters();
413 for(int i=0;i<parameters.length;++i)
414 vars[i].replaceBy(parameters[i]);
415 firstBlock.setParameters(Arrays.copyOfRange(vars, parameters.length, vars.length));
418 BoundVar[] newVars = new BoundVar[getArity()-parameters.length];
419 SSABlock block = new SSABlock(newVars);
420 block.setExit(new Jump(firstBlock.createOccurrence(),
421 ValRef.concat(ValRef.copy(parameters), ValRef.createOccurrences(newVars))));
422 addBlockInFront(block);
426 public void applyTypes(Type[] types) {
427 if(types.length == 0)
429 if(types.length == typeParameters.length) {
430 replace(typeParameters, types);
431 typeParameters = TVar.EMPTY_ARRAY;
434 replace(Arrays.copyOf(typeParameters, types.length), types);
436 Arrays.copyOfRange(typeParameters,
437 types.length, typeParameters.length);
441 public boolean isSimpleEnoughForInline() {
442 return firstBlock == lastBlock &&
443 (firstBlock.firstStatement == null ||
444 (firstBlock.firstStatement == firstBlock.lastStatement
445 && firstBlock.firstStatement instanceof LetApply));
448 public Type getEffect() {
453 public boolean isValue() {
454 return getArity() == 0;
458 public void forValRefs(ValRefVisitor visitor) {
459 for(SSABlock block = firstBlock;
460 block != null; block = block.next)
461 block.forValRefs(visitor);