1 package org.simantics.scl.compiler.internal.codegen.ssa.exits;
3 import java.util.ArrayList;
5 import org.objectweb.asm.Label;
6 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
7 import org.simantics.scl.compiler.constants.BooleanConstant;
8 import org.simantics.scl.compiler.constants.ComparisonFunction;
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.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.SSABlock;
15 import org.simantics.scl.compiler.internal.codegen.ssa.SSAExit;
16 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
17 import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
18 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
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.SSASimplificationContext;
23 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
24 import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
25 import org.simantics.scl.compiler.types.TVar;
26 import org.simantics.scl.compiler.types.Type;
27 import org.simantics.scl.compiler.types.Types;
29 public class If extends SSAExit implements ValRefBinder {
30 private ValRef condition;
31 private ContRef thenTarget;
32 private ContRef elseTarget;
34 public If(int lineNumber, ValRef condition, ContRef thenTarget, ContRef elseTarget) {
36 setCondition(condition);
37 setThenTarget(thenTarget);
38 setElseTarget(elseTarget);
41 public void setCondition(ValRef condition) {
42 this.condition = condition;
43 condition.setParent(this);
46 public void setThenTarget(ContRef thenTarget) {
47 this.thenTarget = thenTarget;
48 thenTarget.setParent(this);
51 public void setElseTarget(ContRef elseTarget) {
52 this.elseTarget = elseTarget;
53 elseTarget.setParent(this);
57 public void generateCode(MethodBuilder mb) {
58 mb.lineNumber(lineNumber);
59 Val binding = condition.getBinding();
60 simplifyTestCode: if(binding instanceof BoundVar) {
61 BoundVar boundVar = (BoundVar)binding;
62 if(!boundVar.generateOnFly)
63 break simplifyTestCode;
64 LetApply apply = (LetApply)boundVar.getParent();
65 Val function = apply.getFunction().getBinding();
66 if(!(function instanceof ComparisonFunction))
67 break simplifyTestCode;
69 Val[] ps = ValRef.getBindings(apply.getParameters());
70 ((ComparisonFunction)function).generateCondition(mb, ps, thenTarget.getBinding(), elseTarget.getBinding());
73 mb.push(condition.getBinding(), Types.BOOLEAN);
74 Label elseLabel = mb.getLabel(elseTarget.getBinding());
75 mb.ifZeroComparisonBranch(elseLabel, "==");
76 mb.jump(thenTarget.getBinding());
77 mb.ensureExists(elseTarget.getBinding());
81 public void toString(PrintingContext context) {
82 context.append("if ");
83 context.append(condition);
84 context.append(" then ");
86 Cont thenCont = thenTarget.getBinding();
87 if(thenCont instanceof SSABlock) {
88 SSABlock thenBlock = (SSABlock)thenCont;
89 if(thenCont.hasMoreThanOneOccurences()) {
90 context.append(thenCont);
91 context.addBlock(thenBlock);
96 thenBlock.bodyToString(context);
97 context.indentation();
101 context.append(thenCont);
105 context.append("else ");
107 Cont elseCont = elseTarget.getBinding();
108 if(elseCont instanceof SSABlock) {
109 SSABlock elseBlock = (SSABlock)elseCont;
110 if(elseCont.hasMoreThanOneOccurences()) {
111 context.append(elseCont);
112 context.addBlock(elseBlock);
113 context.append('\n');
116 context.append('\n');
117 elseBlock.bodyToString(context);
121 context.append(elseCont);
122 context.append('\n');
128 public void validate(SSAValidationContext context) {
129 context.validate(condition);
130 context.validate(elseTarget);
131 context.validate(thenTarget);
132 if(condition.getParent() != this)
133 throw new InternalCompilerError();
134 if(elseTarget.getParent() != this)
135 throw new InternalCompilerError();
136 if(thenTarget.getParent() != this)
137 throw new InternalCompilerError();
138 context.assertEquals(this, condition.getType(), Types.BOOLEAN);
139 context.assertEquals(elseTarget.getBinding().getArity(), 0);
140 context.assertEquals(thenTarget.getBinding().getArity(), 0);
144 public void destroy() {
151 public SSAExit copy(CopyContext context) {
152 If copy = new If(lineNumber,
153 context.copy(condition),
154 context.copy(thenTarget),
155 context.copy(elseTarget));
160 public void replace(TVar[] vars, Type[] replacements) {
161 condition.replace(vars, replacements);
165 public void simplify(SSASimplificationContext context) {
166 Val cond = condition.getBinding();
167 if(cond instanceof BooleanConstant) {
169 if(((BooleanConstant) cond).getValue()) {
170 newExit = new Jump(lineNumber, thenTarget);
174 newExit = new Jump(lineNumber, elseTarget);
178 getParent().setExit(newExit);
179 context.markModified("beta-if");
181 else if(thenTarget.getBinding() == elseTarget.getBinding()) {
184 getParent().setExit(new Jump(lineNumber, thenTarget));
185 context.markModified("equal-branches-if");
190 public void collectFreeVariables(SSAFunction function,
191 ArrayList<ValRef> vars) {
192 condition.collectFreeVariables(function, vars);
196 public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
199 proxy = contRef.getBinding().createProxy(getParent().getParent(), newParameters, oldParameters);
200 ContRef proxyRef = proxy.createOccurrence();
201 if(thenTarget == contRef)
202 setThenTarget(proxyRef);
204 setElseTarget(proxyRef);
209 public SSABlock[] getSuccessors() {
210 Cont thenCont = thenTarget.getBinding();
211 Cont elseCont = elseTarget.getBinding();
212 if(thenCont instanceof SSABlock) {
213 if(elseCont instanceof SSABlock)
214 return new SSABlock[] {(SSABlock)thenCont, (SSABlock)elseCont};
216 return new SSABlock[] {(SSABlock)thenCont};
219 if(elseCont instanceof SSABlock)
220 return new SSABlock[] {(SSABlock)elseCont};
222 return SSABlock.EMPTY_ARRAY;
227 public void forValRefs(ValRefVisitor visitor) {
228 visitor.visit(condition);
232 public void cleanup() {