]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/exits/Switch.java
Added info on backup location to documentation backup.
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / exits / Switch.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.internal.codegen.continuations.BranchRef;
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.Val;
12 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
13 import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
14 import org.simantics.scl.compiler.internal.codegen.ssa.SSAExit;
15 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
16 import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
17 import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
18 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
19 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
20 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
21 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
22 import org.simantics.scl.compiler.types.TVar;
23 import org.simantics.scl.compiler.types.Type;
24 import org.simantics.scl.compiler.types.Types;
25
26 public class Switch extends SSAExit implements ValRefBinder {
27
28     ValRef scrutinee;
29     BranchRef[] branches;
30     
31     public Switch(ValRef scrutinee, BranchRef[] branches) {
32         this.scrutinee = scrutinee;
33         this.branches = branches;
34         scrutinee.setParent(this);
35         for(BranchRef branch : branches)
36             branch.cont.setParent(this);
37     }
38     
39     public ValRef getScrutinee() {
40         return scrutinee;
41     }
42     
43     public BranchRef[] getBranches() {
44         return branches;
45     }
46
47     @Override
48     public void generateCode(MethodBuilder mb) {
49         for(int i=0;i<branches.length;++i) {
50             BranchRef branch = branches[i];
51             if(branch.constructor == null) {
52                 mb.jump(branch.cont);
53             }
54             else if(i < branches.length-1) {                
55                 Label failure = mb.createLabel();
56                 branch.constructor.deconstruct(mb, scrutinee, 
57                         branch.cont.getBinding(), failure);
58                 mb.setLocation(failure);
59             }
60             else {
61                 branch.constructor.deconstruct(mb, scrutinee, 
62                         branch.cont.getBinding(), null);
63             }
64         }
65     }
66
67     @Override
68     public void toString(PrintingContext context) {
69         context.append("switch ");
70         context.append(scrutinee);        
71         for(BranchRef branch : branches) {
72             context.append('\n');
73             context.indentation();
74             if(branch.constructor == null)
75                 context.append("otherwise");
76             else
77                 context.append(branch.constructor.toString());
78             context.append(" -> ");
79             {
80                 Cont cont = branch.cont.getBinding();
81                 if(cont instanceof SSABlock) {
82                     SSABlock block = (SSABlock)cont;
83                     if(cont.hasMoreThanOneOccurences()) {
84                         context.append(cont);
85                         context.append('\n');
86                         context.addBlock(block);
87                     }
88                     else {
89                         block.parametersToString(context);
90                         context.append('\n');
91                         block.bodyToString(context);
92                     }
93                 }
94                 else {
95                     context.append(cont);
96                     context.append('\n');
97                 }
98             }
99         }
100         for(SSABlock block : getSuccessors())
101             context.addBlock(block);
102     }
103
104     @Override
105     public void validate(SSAValidationContext context) {
106         context.validate(scrutinee);
107         if(scrutinee.getParent() != this)
108             throw new InternalCompilerError();
109         for(BranchRef branch : branches) {
110             context.validate(branch.cont);
111             if(branch.cont.getParent() != this)
112                 throw new InternalCompilerError();
113         }
114     }
115
116     @Override
117     public void destroy() {
118         scrutinee.remove();
119         for(BranchRef branch : branches)
120             branch.cont.remove();
121     }
122     
123     @Override
124     public SSAExit copy(CopyContext context) {
125         return new Switch(context.copy(scrutinee), 
126                 BranchRef.copy(context, branches));
127     }
128
129     @Override
130     public void replace(TVar[] vars, Type[] replacements) {
131         scrutinee.replace(vars, replacements);        
132     }
133     
134     @Override
135     public void simplify(SSASimplificationContext context) {
136         if(Types.equals(scrutinee.getType(), Types.BOOLEAN)) {
137             ContRef thenTarget = null;
138             ContRef elseTarget = null;
139             for(BranchRef branch : branches) {
140                 boolean used = false;
141                 if(branch.constructor == null) {
142                     if(thenTarget == null) {
143                         thenTarget = branch.cont;
144                         used = true;
145                     }
146                     if(elseTarget == null) {
147                         elseTarget = branch.cont;
148                         used = true;
149                     }
150                 }
151                 else if(((BooleanConstant)branch.constructor).getValue()) {
152                     if(thenTarget == null) {
153                         thenTarget = branch.cont;
154                         used = true;
155                     }
156                 }
157                 else {
158                     if(elseTarget == null) {
159                         elseTarget = branch.cont;
160                         used = true;
161                     }
162                 }
163                 if(!used)
164                     branch.cont.remove();
165             }
166             
167             // This may be possible if match compiler has
168             // determined that one of the branches is not possible.
169             if(elseTarget == null) 
170                 elseTarget = thenTarget;
171             else if(thenTarget == null) 
172                 thenTarget = elseTarget;
173             
174             // Replace switch by jump or if
175             SSAExit newExit;
176             if(thenTarget == elseTarget) {
177                 scrutinee.remove();
178                 newExit = new Jump(thenTarget);
179             }
180             else {
181                 newExit = new If(scrutinee, 
182                         thenTarget, 
183                         elseTarget);
184             }
185             getParent().setExit(newExit);
186             context.markModified("switch-to-if");
187             newExit.simplify(context);
188         }
189         else if(branches.length == 1 && branches[0].constructor == null) {
190             scrutinee.remove();
191             getParent().setExit(new Jump(branches[0].cont));
192         }
193     }
194
195     @Override
196     public void collectFreeVariables(SSAFunction function,
197             ArrayList<ValRef> vars) {
198         scrutinee.collectFreeVariables(function, vars);
199     }
200     
201     @Override
202     public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
203             Cont proxy) {
204         if(proxy == null)
205             proxy = contRef.getBinding().createProxy(getParent().getParent(), newParameters, oldParameters);
206         ContRef proxyRef = proxy.createOccurrence();
207         proxyRef.setParent(this);
208         for(BranchRef branch : branches) {
209             if(branch.cont == contRef) {
210                 branch.cont = proxyRef;
211                 break;
212             }
213         }
214         return proxy;
215     }
216
217     @Override
218     public SSABlock[] getSuccessors() {
219         ArrayList<SSABlock> result = new ArrayList<SSABlock>(branches.length);
220         for(BranchRef branch : branches) {
221             Cont cont = branch.cont.getBinding();
222             if(cont instanceof SSABlock)
223                 result.add((SSABlock)cont);
224         }
225         return result.toArray(new SSABlock[result.size()]);
226     }
227 }