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(ValRef condition, ContRef thenTarget, ContRef elseTarget) {
35 setCondition(condition);
36 setThenTarget(thenTarget);
37 setElseTarget(elseTarget);
40 public void setCondition(ValRef condition) {
41 this.condition = condition;
42 condition.setParent(this);
45 public void setThenTarget(ContRef thenTarget) {
46 this.thenTarget = thenTarget;
47 thenTarget.setParent(this);
50 public void setElseTarget(ContRef elseTarget) {
51 this.elseTarget = elseTarget;
52 elseTarget.setParent(this);
56 public void generateCode(MethodBuilder mb) {
57 Val binding = condition.getBinding();
58 simplifyTestCode: if(binding instanceof BoundVar) {
59 BoundVar boundVar = (BoundVar)binding;
60 if(!boundVar.generateOnFly)
61 break simplifyTestCode;
62 LetApply apply = (LetApply)boundVar.getParent();
63 Val function = apply.getFunction().getBinding();
64 if(!(function instanceof ComparisonFunction))
65 break simplifyTestCode;
67 Val[] ps = ValRef.getBindings(apply.getParameters());
68 ((ComparisonFunction)function).generateCondition(mb, ps, thenTarget.getBinding(), elseTarget.getBinding());
71 mb.push(condition.getBinding(), Types.BOOLEAN);
72 Label elseLabel = mb.getLabel(elseTarget.getBinding());
73 mb.ifZeroComparisonBranch(elseLabel, "==");
74 mb.jump(thenTarget.getBinding());
75 mb.ensureExists(elseTarget.getBinding());
79 public void toString(PrintingContext context) {
80 context.append("if ");
81 context.append(condition);
82 context.append(" then ");
84 Cont thenCont = thenTarget.getBinding();
85 if(thenCont instanceof SSABlock) {
86 SSABlock thenBlock = (SSABlock)thenCont;
87 if(thenCont.hasMoreThanOneOccurences()) {
88 context.append(thenCont);
89 context.addBlock(thenBlock);
94 thenBlock.bodyToString(context);
95 context.indentation();
99 context.append(thenCont);
103 context.append("else ");
105 Cont elseCont = elseTarget.getBinding();
106 if(elseCont instanceof SSABlock) {
107 SSABlock elseBlock = (SSABlock)elseCont;
108 if(elseCont.hasMoreThanOneOccurences()) {
109 context.append(elseCont);
110 context.addBlock(elseBlock);
111 context.append('\n');
114 context.append('\n');
115 elseBlock.bodyToString(context);
119 context.append(elseCont);
120 context.append('\n');
126 public void validate(SSAValidationContext context) {
127 context.validate(condition);
128 context.validate(elseTarget);
129 context.validate(thenTarget);
130 if(condition.getParent() != this)
131 throw new InternalCompilerError();
132 if(elseTarget.getParent() != this)
133 throw new InternalCompilerError();
134 if(thenTarget.getParent() != this)
135 throw new InternalCompilerError();
136 context.assertEquals(this, condition.getType(), Types.BOOLEAN);
137 context.assertEquals(elseTarget.getBinding().getArity(), 0);
138 context.assertEquals(thenTarget.getBinding().getArity(), 0);
142 public void destroy() {
149 public SSAExit copy(CopyContext context) {
150 return new If(context.copy(condition),
151 context.copy(thenTarget),
152 context.copy(elseTarget));
156 public void replace(TVar[] vars, Type[] replacements) {
157 condition.replace(vars, replacements);
161 public void simplify(SSASimplificationContext context) {
162 Val cond = condition.getBinding();
163 if(cond instanceof BooleanConstant) {
165 if(((BooleanConstant) cond).getValue()) {
166 newExit = new Jump(thenTarget);
170 newExit = new Jump(elseTarget);
174 getParent().setExit(newExit);
175 context.markModified("beta-if");
177 else if(thenTarget.getBinding() == elseTarget.getBinding()) {
180 getParent().setExit(new Jump(thenTarget));
181 context.markModified("equal-branches-if");
186 public void collectFreeVariables(SSAFunction function,
187 ArrayList<ValRef> vars) {
188 condition.collectFreeVariables(function, vars);
192 public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
195 proxy = contRef.getBinding().createProxy(getParent().getParent(), newParameters, oldParameters);
196 ContRef proxyRef = proxy.createOccurrence();
197 if(thenTarget == contRef)
198 setThenTarget(proxyRef);
200 setElseTarget(proxyRef);
205 public SSABlock[] getSuccessors() {
206 Cont thenCont = thenTarget.getBinding();
207 Cont elseCont = elseTarget.getBinding();
208 if(thenCont instanceof SSABlock) {
209 if(elseCont instanceof SSABlock)
210 return new SSABlock[] {(SSABlock)thenCont, (SSABlock)elseCont};
212 return new SSABlock[] {(SSABlock)thenCont};
215 if(elseCont instanceof SSABlock)
216 return new SSABlock[] {(SSABlock)elseCont};
218 return SSABlock.EMPTY_ARRAY;
223 public void forValRefs(ValRefVisitor visitor) {
224 visitor.visit(condition);
228 public void cleanup() {