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