]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/exits/If.java
SCL compiler generates line numbers to bytecode
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / exits / If.java
1 package org.simantics.scl.compiler.internal.codegen.ssa.exits;
2
3 import java.util.ArrayList;
4
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;
28
29 public class If extends SSAExit implements ValRefBinder {
30     private ValRef condition;
31     private ContRef thenTarget;
32     private ContRef elseTarget;
33     
34     public If(int lineNumber, ValRef condition, ContRef thenTarget, ContRef elseTarget) {
35         super(lineNumber);
36         setCondition(condition);
37         setThenTarget(thenTarget);
38         setElseTarget(elseTarget);
39     }
40     
41     public void setCondition(ValRef condition) {
42         this.condition = condition;
43         condition.setParent(this);
44     }
45     
46     public void setThenTarget(ContRef thenTarget) {
47         this.thenTarget = thenTarget;
48         thenTarget.setParent(this);
49     }
50     
51     public void setElseTarget(ContRef elseTarget) {
52         this.elseTarget = elseTarget;
53         elseTarget.setParent(this);
54     }
55
56     @Override
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;
68
69             Val[] ps = ValRef.getBindings(apply.getParameters());
70             ((ComparisonFunction)function).generateCondition(mb, ps, thenTarget.getBinding(), elseTarget.getBinding());
71             return;
72         }
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());
78     }
79
80     @Override
81     public void toString(PrintingContext context) {
82         context.append("if ");
83         context.append(condition);
84         context.append(" then ");
85         {
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);
92                     context.append(' ');
93                 }
94                 else {
95                     context.append('\n');
96                     thenBlock.bodyToString(context);
97                     context.indentation();
98                 }
99             }
100             else {
101                 context.append(thenCont);
102                 context.append(' ');
103             }
104         }        
105         context.append("else ");
106         {
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');
114                 }
115                 else {
116                     context.append('\n');
117                     elseBlock.bodyToString(context);
118                 }
119             }
120             else {
121                 context.append(elseCont);
122                 context.append('\n');
123             }
124         }
125     }
126
127     @Override
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);
141     }
142
143     @Override
144     public void destroy() {
145         condition.remove();
146         elseTarget.remove();
147         thenTarget.remove();
148     }
149
150     @Override
151     public SSAExit copy(CopyContext context) {
152         If copy = new If(lineNumber,
153                 context.copy(condition),
154                 context.copy(thenTarget),
155                 context.copy(elseTarget));
156         return copy;
157     }
158     
159     @Override
160     public void replace(TVar[] vars, Type[] replacements) {
161         condition.replace(vars, replacements);        
162     }
163     
164     @Override
165     public void simplify(SSASimplificationContext context) {
166         Val cond = condition.getBinding();
167         if(cond instanceof BooleanConstant) {
168             SSAExit newExit;
169             if(((BooleanConstant) cond).getValue()) {
170                 newExit = new Jump(lineNumber, thenTarget);
171                 elseTarget.remove();
172             }
173             else {
174                 newExit = new Jump(lineNumber, elseTarget);
175                 thenTarget.remove();
176             }
177             condition.remove();
178             getParent().setExit(newExit);
179             context.markModified("beta-if");
180         }
181         else if(thenTarget.getBinding() == elseTarget.getBinding()) {
182             elseTarget.remove();
183             condition.remove();
184             getParent().setExit(new Jump(lineNumber, thenTarget));
185             context.markModified("equal-branches-if");
186         }
187     }
188
189     @Override
190     public void collectFreeVariables(SSAFunction function,
191             ArrayList<ValRef> vars) {
192         condition.collectFreeVariables(function, vars);
193     }
194     
195     @Override
196     public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
197             Cont proxy) {
198         if(proxy == null)
199             proxy = contRef.getBinding().createProxy(getParent().getParent(), newParameters, oldParameters);
200         ContRef proxyRef = proxy.createOccurrence();
201         if(thenTarget == contRef)
202             setThenTarget(proxyRef);
203         else
204             setElseTarget(proxyRef);
205         return proxy;
206     }
207
208     @Override
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};
215             else
216                 return new SSABlock[] {(SSABlock)thenCont};
217         }
218         else {
219             if(elseCont instanceof SSABlock)
220                 return new SSABlock[] {(SSABlock)elseCont};
221             else
222                 return SSABlock.EMPTY_ARRAY;
223         }
224     }
225
226     @Override
227     public void forValRefs(ValRefVisitor visitor) {
228         visitor.visit(condition);
229     }
230
231     @Override
232     public void cleanup() {
233         condition.remove();
234     }
235 }