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.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;
26 public class Switch extends SSAExit implements ValRefBinder {
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);
39 public ValRef getScrutinee() {
43 public BranchRef[] getBranches() {
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) {
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);
61 branch.constructor.deconstruct(mb, scrutinee,
62 branch.cont.getBinding(), null);
68 public void toString(PrintingContext context) {
69 context.append("switch ");
70 context.append(scrutinee);
71 for(BranchRef branch : branches) {
73 context.indentation();
74 if(branch.constructor == null)
75 context.append("otherwise");
77 context.append(branch.constructor.toString());
78 context.append(" -> ");
80 Cont cont = branch.cont.getBinding();
81 if(cont instanceof SSABlock) {
82 SSABlock block = (SSABlock)cont;
83 if(cont.hasMoreThanOneOccurences()) {
86 context.addBlock(block);
89 block.parametersToString(context);
91 block.bodyToString(context);
100 for(SSABlock block : getSuccessors())
101 context.addBlock(block);
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();
117 public void destroy() {
119 for(BranchRef branch : branches)
120 branch.cont.remove();
124 public SSAExit copy(CopyContext context) {
125 return new Switch(context.copy(scrutinee),
126 BranchRef.copy(context, branches));
130 public void replace(TVar[] vars, Type[] replacements) {
131 scrutinee.replace(vars, replacements);
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;
146 if(elseTarget == null) {
147 elseTarget = branch.cont;
151 else if(((BooleanConstant)branch.constructor).getValue()) {
152 if(thenTarget == null) {
153 thenTarget = branch.cont;
158 if(elseTarget == null) {
159 elseTarget = branch.cont;
164 branch.cont.remove();
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;
174 // Replace switch by jump or if
176 if(thenTarget == elseTarget) {
178 newExit = new Jump(thenTarget);
181 newExit = new If(scrutinee,
185 getParent().setExit(newExit);
186 context.markModified("switch-to-if");
187 newExit.simplify(context);
189 else if(branches.length == 1 && branches[0].constructor == null) {
191 getParent().setExit(new Jump(branches[0].cont));
196 public void collectFreeVariables(SSAFunction function,
197 ArrayList<ValRef> vars) {
198 scrutinee.collectFreeVariables(function, vars);
202 public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
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;
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);
225 return result.toArray(new SSABlock[result.size()]);