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;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 public final class SSAFunction extends SSAClosure {
33 private static final Logger LOGGER = LoggerFactory.getLogger(SSAFunction.class);
35 TVar[] typeParameters;
39 ReturnCont returnCont;
41 public SSAFunction(TVar[] typeParameters, Type effect, Type returnType) {
42 this(typeParameters, effect, new ReturnCont(returnType));
45 public SSAFunction(TVar[] typeParameters, Type effect, ReturnCont returnCont) {
46 this.typeParameters = typeParameters;
47 this.returnCont = returnCont;
48 this.effect = Types.canonical(effect);
49 returnCont.setParent(this);
52 public boolean hasEffect() {
53 return effect != Types.NO_EFFECTS;
56 public void addBlock(SSABlock block) {
58 if(lastBlock == null) {
59 firstBlock = lastBlock = block;
60 block.next = block.prev = null;
63 lastBlock.next = block;
64 block.prev = lastBlock;
70 public void addBlockInFront(SSABlock block) {
72 if(firstBlock == null) {
73 firstBlock = lastBlock = block;
74 block.next = block.prev = null;
77 firstBlock.prev = block;
78 block.next = firstBlock;
84 public ReturnCont getReturnCont() {
88 public TVar[] getTypeParameters() {
89 return typeParameters;
92 public SSABlock getFirstBlock() {
96 public void generateCode(MethodBuilder mb) {
97 JavaTypeTranslator tt = mb.getJavaTypeTranslator();
98 for(int i=0,j=0;i<firstBlock.parameters.length;++i)
99 if(!tt.toTypeDesc(firstBlock.parameters[i].getType()).equals(TypeDesc.VOID))
100 mb.setLocalVariable(firstBlock.parameters[i], mb.getParameter(j++));
101 generateCodeWithAlreadyPreparedParameters(mb);
104 public void generateCodeWithAlreadyPreparedParameters(MethodBuilder mb) {
105 for(SSABlock block = firstBlock; block != null; block = block.next)
107 firstBlock.generateCode(mb);
110 public void toString(PrintingContext context) {
111 context.indentation();
112 if(typeParameters.length > 0) {
114 boolean first = true;
115 for(TVar var : typeParameters) {
122 context.append("> ");
125 context.append(effect);
128 context.append("RETURNS ");
129 context.append(returnCont.getType());
130 context.append('\n');
133 context.pushBlockQueue();
134 context.addBlock(getFirstBlock());
136 SSABlock block = context.pollBlock();
139 block.toString(context);
141 context.popBlockQueue();
145 public String toString() {
146 PrintingContext context = new PrintingContext();
148 return context.toString();
151 public void validate(SSAValidationContext context) {
152 if(target instanceof BoundVar && ((BoundVar)target).parent != this)
153 throw new InternalCompilerError();
155 // Add valid type variables
156 for(TVar var : typeParameters)
157 context.validTypeVariables.add(var);
159 // Add valid variables and continuations
160 context.validContinuations.add(returnCont);
161 for(SSABlock block = firstBlock; block != null; block = block.next) {
162 context.validContinuations.add(block);
163 for(BoundVar parameter : block.parameters)
164 context.validBoundVariables.add(parameter);
165 for(SSAStatement stat = block.firstStatement; stat != null; stat = stat.next)
166 stat.addBoundVariablesTo(context);
170 for(SSABlock block = firstBlock; block != null; block = block.next)
171 block.validate(context);
172 context.validate(returnCont);
174 //context.reset(); // FIXME not good when there are nested functions
178 public void simplify(SSASimplificationContext context) {
179 for(SSABlock block = firstBlock; block != null; block = block.next)
180 block.simplify(context);
181 if(firstBlock == lastBlock && firstBlock.firstStatement == firstBlock.lastStatement) {
182 if(firstBlock.firstStatement instanceof LetApply)
183 simplifySingleApply(context);
184 else if(firstBlock.firstStatement instanceof LetFunctions)
185 simplifySingleLambda(context);
191 * Simplifies the following kind of function definition
196 private void simplifySingleApply(SSASimplificationContext context) {
197 if(!(parent instanceof LetFunctions) || parent.getFirstClosure().next != null)
199 LetApply apply = (LetApply)firstBlock.firstStatement;
200 if(!(firstBlock.exit instanceof Jump))
202 Jump exit = (Jump)firstBlock.exit;
203 if(exit.getTarget().getBinding() != returnCont)
205 if(exit.getParameter(0).getBinding() != apply.getTarget())
207 BoundVar[] functionParameters = getParameters();
208 ValRef[] applyParameters = apply.getParameters();
209 if(functionParameters.length > applyParameters.length)
211 int extraApplyParameters = applyParameters.length - functionParameters.length;
212 for(int i=0;i<functionParameters.length;++i)
213 if(!representSameValues(functionParameters[i], applyParameters[extraApplyParameters+i]))
215 for(int i=0;i<extraApplyParameters;++i) {
216 Val b = applyParameters[i].getBinding();
217 if(b instanceof BoundVar) {
218 BoundVar bv = (BoundVar)b;
219 if(bv == target || bv.getParent() == firstBlock)
223 if(!(target instanceof BoundVar))
228 LetFunctions binder = (LetFunctions)parent;
229 SSAFunction parentFunction = binder.getParentFunction();
230 if(extraApplyParameters > 0) {
231 //System.out.println("-------------------------------------------------------------");
232 //System.out.println(parentFunction);
233 //System.out.println("-------------------------------------------------------------");
234 apply.setTarget((BoundVar)target);
235 apply.setParameters(Arrays.copyOf(applyParameters, extraApplyParameters));
236 apply.insertBefore(binder);
238 //System.out.println(parentFunction);
239 //System.out.println("-------------------------------------------------------------");
243 ((BoundVar)target).replaceBy(apply.getFunction());
245 context.markModified("SSAFunction.eta-reduce");
248 private boolean representSameValues(BoundVar boundVar, ValRef valRef) {
249 Val val = valRef.getBinding();
250 if(val == boundVar && valRef.getTypeParameters().length == 0)
252 if(val instanceof NoRepConstant && Types.equals(valRef.getType(), boundVar.getType()))
258 * Simplifies the following kind of function definition
263 private void simplifySingleLambda(SSASimplificationContext context) {
264 LetFunctions letF = (LetFunctions)firstBlock.firstStatement;
265 if(!(letF.getFirstClosure() instanceof SSAFunction))
267 SSAFunction f = (SSAFunction)letF.getFirstClosure();
268 if(f.getNext() != null)
270 Val fVal = f.getTarget();
271 if(!firstBlock.exit.isJump(getReturnCont(), fVal))
273 if(fVal.hasMoreThanOneOccurences())
274 return; // Possible if function is recursive and refers to itself
276 return; // Not probably possible (?)
279 for(SSABlock block = f.firstBlock; block != null; block = block.next)
281 lastBlock.next = f.firstBlock;
282 f.firstBlock.prev = lastBlock;
283 lastBlock = f.lastBlock;
285 firstBlock.firstStatement = firstBlock.lastStatement = null;
286 setReturnCont(f.getReturnCont());
288 BoundVar[] newParameters = BoundVar.copy(f.firstBlock.parameters);
289 firstBlock.setParameters(BoundVar.concat(getParameters(), newParameters));
290 firstBlock.setExit(new Jump(f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters)));
291 context.markModified("SSAFunction.simplify-simple-lambda");
294 public void setReturnCont(ReturnCont returnCont) {
295 this.returnCont = returnCont;
296 returnCont.setParent(this);
299 public ValRef isEqualToConstant() {
300 if(firstBlock.parameters.length > 0)
302 if(firstBlock != lastBlock)
304 if(firstBlock.firstStatement != null)
306 if(!(firstBlock.exit instanceof Jump))
308 Jump exit = (Jump)firstBlock.exit;
309 if(exit.getTarget().getBinding() != returnCont)
311 return exit.getParameters()[0];
314 public BoundVar[] getParameters() {
315 return firstBlock.parameters;
318 public Type[] getParameterTypes() {
319 return Types.getTypes(firstBlock.parameters);
322 public int getArity() {
323 return firstBlock.parameters.length;
327 public void markGenerateOnFly() {
328 for(SSABlock block = firstBlock; block != null; block = block.next)
329 block.markGenerateOnFly();
333 public SSAClosure copy(CopyContext context) {
334 TVar[] newTypeParameters = context.copyParameters(typeParameters);
335 SSAFunction newFunction = new SSAFunction(newTypeParameters, effect, context.copy(returnCont));
336 for(SSABlock block = firstBlock;
337 block != null; block = block.next)
338 newFunction.addBlock(context.copy(block));
343 public void replace(TVar[] vars, Type[] replacements) {
344 returnCont.replace(vars, replacements);
345 for(SSABlock block = firstBlock;
346 block != null; block = block.next)
347 block.replace(vars, replacements);
350 public void setTypeParameters(TVar[] typeParameters) {
351 this.typeParameters = typeParameters;
355 public Type getType() {
356 Type type = returnCont.getType();
357 type = Types.functionE(
358 Types.getTypes(firstBlock.parameters),
361 type = Types.forAll(typeParameters, type);
365 public void mergeBlocks(SSAFunction function) {
367 throw new InternalCompilerError();
368 SSABlock block = function.firstBlock;
369 while(block != null) {
370 SSABlock next = block.next;
376 public Type getReturnType() {
377 return returnCont.getType();
381 public void destroy() {
382 for(SSABlock block = firstBlock;
383 block != null; block = block.next)
388 public void collectFreeVariables(ArrayList<ValRef> vars) {
389 for(SSABlock block = firstBlock;
390 block != null; block = block.next)
391 block.collectFreeVariables(this, vars);
395 public void lambdaLift(SSALambdaLiftingContext context) {
396 for(SSABlock block = firstBlock;
397 block != null; block = block.next)
398 block.lambdaLift(context);
402 public void parametrize(BoundVar[] parameters) {
404 for(ContRef ref = firstBlock.getOccurrence(); ref != null; ref = ref.getNext())
405 proxy = ref.addParametersInFront(parameters, firstBlock.parameters, proxy);
407 firstBlock.parameters = BoundVar.concat(parameters, firstBlock.parameters);
408 for(BoundVar parameter : parameters)
409 parameter.parent = firstBlock;
412 public void apply(ValRef[] parameters) {
413 if(parameters.length == 0)
415 if(firstBlock.hasNoOccurences()) {
416 BoundVar[] vars = firstBlock.getParameters();
417 for(int i=0;i<parameters.length;++i)
418 vars[i].replaceBy(parameters[i]);
419 firstBlock.setParameters(Arrays.copyOfRange(vars, parameters.length, vars.length));
422 BoundVar[] newVars = new BoundVar[getArity()-parameters.length];
423 SSABlock block = new SSABlock(newVars);
424 block.setExit(new Jump(firstBlock.createOccurrence(),
425 ValRef.concat(ValRef.copy(parameters), ValRef.createOccurrences(newVars))));
426 addBlockInFront(block);
430 public void applyTypes(Type[] types) {
431 if(types.length == 0)
433 if(types.length == typeParameters.length) {
434 replace(typeParameters, types);
435 typeParameters = TVar.EMPTY_ARRAY;
438 replace(Arrays.copyOf(typeParameters, types.length), types);
440 Arrays.copyOfRange(typeParameters,
441 types.length, typeParameters.length);
445 public boolean isSimpleEnoughForInline() {
446 return firstBlock == lastBlock &&
447 (firstBlock.firstStatement == null ||
448 (firstBlock.firstStatement == firstBlock.lastStatement
449 && firstBlock.firstStatement instanceof LetApply));
452 public Type getEffect() {
457 public boolean isValue() {
458 return getArity() == 0;
462 public void forValRefs(ValRefVisitor visitor) {
463 for(SSABlock block = firstBlock;
464 block != null; block = block.next)
465 block.forValRefs(visitor);
469 public void cleanup() {
470 for(SSABlock block = firstBlock; block != null; block = block.next)