]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/exits/Switch.java
Merged changes from feature/scl to master.
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / exits / Switch.java
index a6674eb1b3b265233062becd15d11a19ece2a829..0bcb3dd596e3bc03cbc91779d40232ce3d787c02 100644 (file)
@@ -5,6 +5,7 @@ import java.util.ArrayList;
 import org.objectweb.asm.Label;
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.constants.BooleanConstant;
+import org.simantics.scl.compiler.constants.IntegerConstant;
 import org.simantics.scl.compiler.internal.codegen.continuations.BranchRef;
 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
@@ -19,6 +20,7 @@ import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
 import org.simantics.scl.compiler.types.TVar;
 import org.simantics.scl.compiler.types.Type;
 import org.simantics.scl.compiler.types.Types;
@@ -43,24 +45,59 @@ public class Switch extends SSAExit implements ValRefBinder {
     public BranchRef[] getBranches() {
         return branches;
     }
+    
+    private boolean isIntegerSwitch() {
+        if(scrutinee.getType() != Types.INTEGER)
+            return false;
+        for(BranchRef branch : branches)
+            if(branch.constructor != null && !(branch.constructor instanceof IntegerConstant))
+                return false;
+        return true;
+    }
+    
+    private void generateIntegerSwitch(MethodBuilder mb) {
+        int defaultId;
+        for(defaultId=0;defaultId<branches.length-1&&branches[defaultId].constructor!=null;++defaultId);
+        int[] values = new int[defaultId];
+        Label[] labels = new Label[defaultId];
+        Cont[] continuations = new Cont[defaultId+1];
+        for(int i=0;i<defaultId;++i) {
+            values[i] = ((IntegerConstant)branches[i].constructor).getValue();
+            Cont cont = branches[i].cont.getBinding();
+            labels[i] = mb.getLabel(cont);
+            continuations[i] = cont;
+        }
+        Label defaultLabel;
+        {
+            Cont cont = branches[defaultId].cont.getBinding();
+            defaultLabel = mb.getLabel(cont);
+            continuations[defaultId] = cont;
+        }
+        mb.push(scrutinee, Types.INTEGER);
+        mb.switch_(values, labels, defaultLabel);
+        for(Cont cont : continuations)
+            mb.ensureExists(cont);
+    }
 
     @Override
     public void generateCode(MethodBuilder mb) {
+        if(isIntegerSwitch()) {
+            generateIntegerSwitch(mb);
+            return;
+        }
         for(int i=0;i<branches.length;++i) {
             BranchRef branch = branches[i];
-            if(branch.constructor == null) {
+            if(branch.constructor == null)
                 mb.jump(branch.cont);
-            }
             else if(i < branches.length-1) {                
                 Label failure = mb.createLabel();
                 branch.constructor.deconstruct(mb, scrutinee, 
                         branch.cont.getBinding(), failure);
                 mb.setLocation(failure);
             }
-            else {
+            else
                 branch.constructor.deconstruct(mb, scrutinee, 
                         branch.cont.getBinding(), null);
-            }
         }
     }
 
@@ -80,16 +117,16 @@ public class Switch extends SSAExit implements ValRefBinder {
                 Cont cont = branch.cont.getBinding();
                 if(cont instanceof SSABlock) {
                     SSABlock block = (SSABlock)cont;
-                    if(cont.hasMoreThanOneOccurences()) {
+                    //if(cont.hasMoreThanOneOccurences()) {
                         context.append(cont);
                         context.append('\n');
                         context.addBlock(block);
-                    }
+                    /*}
                     else {
                         block.parametersToString(context);
                         context.append('\n');
                         block.bodyToString(context);
-                    }
+                    }*/
                 }
                 else {
                     context.append(cont);
@@ -224,4 +261,9 @@ public class Switch extends SSAExit implements ValRefBinder {
         }
         return result.toArray(new SSABlock[result.size()]);
     }
+
+    @Override
+    public void forValRefs(ValRefVisitor visitor) {
+        visitor.visit(scrutinee);
+    }
 }