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.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;
28 public class Switch extends SSAExit implements ValRefBinder {
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);
41 public ValRef getScrutinee() {
45 public BranchRef[] getBranches() {
49 private boolean isIntegerSwitch() {
50 if(scrutinee.getType() != Types.INTEGER)
52 for(BranchRef branch : branches)
53 if(branch.constructor != null && !(branch.constructor instanceof IntegerConstant))
58 private void generateIntegerSwitch(MethodBuilder mb) {
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;
72 Cont cont = branches[defaultId].cont.getBinding();
73 defaultLabel = mb.getLabel(cont);
74 continuations[defaultId] = cont;
76 mb.push(scrutinee, Types.INTEGER);
77 mb.switch_(values, labels, defaultLabel);
78 for(Cont cont : continuations)
79 mb.ensureExists(cont);
83 public void generateCode(MethodBuilder mb) {
84 if(isIntegerSwitch()) {
85 generateIntegerSwitch(mb);
88 for(int i=0;i<branches.length;++i) {
89 BranchRef branch = branches[i];
90 if(branch.constructor == null)
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);
99 branch.constructor.deconstruct(mb, scrutinee,
100 branch.cont.getBinding(), null);
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");
114 context.append(branch.constructor.toString());
115 context.append(" -> ");
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);
126 block.parametersToString(context);
127 context.append('\n');
128 block.bodyToString(context);
132 context.append(cont);
133 context.append('\n');
137 for(SSABlock block : getSuccessors())
138 context.addBlock(block);
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();
154 public void destroy() {
156 for(BranchRef branch : branches)
157 branch.cont.remove();
161 public SSAExit copy(CopyContext context) {
162 return new Switch(context.copy(scrutinee),
163 BranchRef.copy(context, branches));
167 public void replace(TVar[] vars, Type[] replacements) {
168 scrutinee.replace(vars, replacements);
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;
183 if(elseTarget == null) {
184 elseTarget = branch.cont;
188 else if(((BooleanConstant)branch.constructor).getValue()) {
189 if(thenTarget == null) {
190 thenTarget = branch.cont;
195 if(elseTarget == null) {
196 elseTarget = branch.cont;
201 branch.cont.remove();
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;
211 // Replace switch by jump or if
213 if(thenTarget == elseTarget) {
215 newExit = new Jump(thenTarget);
218 newExit = new If(scrutinee,
222 getParent().setExit(newExit);
223 context.markModified("switch-to-if");
224 newExit.simplify(context);
226 else if(branches.length == 1 && branches[0].constructor == null) {
228 getParent().setExit(new Jump(branches[0].cont));
233 public void collectFreeVariables(SSAFunction function,
234 ArrayList<ValRef> vars) {
235 scrutinee.collectFreeVariables(function, vars);
239 public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
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;
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);
262 return result.toArray(new SSABlock[result.size()]);
266 public void forValRefs(ValRefVisitor visitor) {
267 visitor.visit(scrutinee);