[ir][msl] Emit switch instructions

Add support for the ir switch instructions.

Bug: tint:1967
Change-Id: I838527ea04cea2bfeef0b5c528f58166a0d6339e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162264
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 4bf5b2f..dbe51d4 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -44,6 +44,7 @@
 #include "src/tint/lang/core/ir/discard.h"
 #include "src/tint/lang/core/ir/exit_if.h"
 #include "src/tint/lang/core/ir/exit_loop.h"
+#include "src/tint/lang/core/ir/exit_switch.h"
 #include "src/tint/lang/core/ir/ice.h"
 #include "src/tint/lang/core/ir/if.h"
 #include "src/tint/lang/core/ir/let.h"
@@ -53,6 +54,7 @@
 #include "src/tint/lang/core/ir/next_iteration.h"
 #include "src/tint/lang/core/ir/return.h"
 #include "src/tint/lang/core/ir/store.h"
+#include "src/tint/lang/core/ir/switch.h"
 #include "src/tint/lang/core/ir/unreachable.h"
 #include "src/tint/lang/core/ir/user_call.h"
 #include "src/tint/lang/core/ir/validator.h"
@@ -282,6 +284,8 @@
                 [&](core::ir::NextIteration*) { /* do nothing */ },  //
                 [&](core::ir::BreakIf* b) { EmitBreakIf(b); },       //
                 [&](core::ir::ExitLoop*) { EmitExitLoop(); },        //
+                [&](core::ir::ExitSwitch*) { EmitExitSwitch(); },    //
+                [&](core::ir::Switch* s) { EmitSwitch(s); },         //
 
                 [&](core::ir::Bitcast*) { MaybeEmitInstruction(inst); },    //
                 [&](core::ir::Unary*) { MaybeEmitInstruction(inst); },      //
@@ -520,6 +524,39 @@
         Line() << "}";
     }
 
+    void EmitExitSwitch() { Line() << "break;"; }
+
+    void EmitSwitch(core::ir::Switch* s) {
+        {
+            auto out = Line();
+            out << "switch(";
+            EmitValue(out, s->Condition());
+            out << ") {";
+        }
+        {
+            ScopedIndent blk(current_buffer_);
+            for (auto& case_ : s->Cases()) {
+                for (auto& sel : case_.selectors) {
+                    if (sel.IsDefault()) {
+                        Line() << "default:";
+                    } else {
+                        auto out = Line();
+                        out << "case ";
+                        EmitValue(out, sel.val);
+                        out << ":";
+                    }
+                }
+                Line() << "{";
+                {
+                    ScopedIndent ci(current_buffer_);
+                    EmitBlock(case_.block);
+                }
+                Line() << "}";
+            }
+        }
+        Line() << "}";
+    }
+
     /// Emit an if instruction
     /// @param if_ the if instruction
     void EmitIf(core::ir::If* if_) {
diff --git a/test/tint/loops/continue_in_switch.wgsl.expected.ir.msl b/test/tint/loops/continue_in_switch.wgsl.expected.ir.msl
index cdbf128..88c3be7 100644
--- a/test/tint/loops/continue_in_switch.wgsl.expected.ir.msl
+++ b/test/tint/loops/continue_in_switch.wgsl.expected.ir.msl
@@ -1,9 +1,27 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void f() {
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 4)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          i = (i + 1);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 1);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.ir.msl b/test/tint/loops/multiple_continues.wgsl.expected.ir.msl
index cdbf128..de48573 100644
--- a/test/tint/loops/multiple_continues.wgsl.expected.ir.msl
+++ b/test/tint/loops/multiple_continues.wgsl.expected.ir.msl
@@ -1,9 +1,37 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          i = (i + 1);
+          continue;
+        }
+        case 1:
+        {
+          i = (i + 1);
+          continue;
+        }
+        case 2:
+        {
+          i = (i + 1);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 1);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.ir.msl b/test/tint/loops/multiple_switch.wgsl.expected.ir.msl
index cdbf128..6a761f7 100644
--- a/test/tint/loops/multiple_switch.wgsl.expected.ir.msl
+++ b/test/tint/loops/multiple_switch.wgsl.expected.ir.msl
@@ -1,9 +1,39 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  int i = 0;
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          i = (i + 1);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      switch(i) {
+        case 0:
+        {
+          i = (i + 1);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 1);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.ir.msl b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.ir.msl
index cdbf128..8921168 100644
--- a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.ir.msl
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.ir.msl
@@ -1,9 +1,38 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      {
+        int j = 0;
+        while(true) {
+          if ((j < 2)) {
+          } else {
+            break;
+          }
+          switch(i) {
+            case 0:
+            {
+              j = (j + 2);
+              continue;
+            }
+            default:
+            {
+              break;
+            }
+          }
+          j = (j + 2);
+          continue;
+        }
+      }
+      i = (i + 2);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.ir.msl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.ir.msl
index cdbf128..6dbcb48 100644
--- a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.ir.msl
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.ir.msl
@@ -1,9 +1,49 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          {
+            int j = 0;
+            while(true) {
+              if ((j < 2)) {
+              } else {
+                break;
+              }
+              switch(j) {
+                case 0:
+                {
+                  j = (j + 2);
+                  continue;
+                }
+                default:
+                {
+                  break;
+                }
+              }
+              j = (j + 2);
+              continue;
+            }
+          }
+          i = (i + 2);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 2);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.ir.msl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.ir.msl
index cdbf128..2fea1a7 100644
--- a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.ir.msl
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.ir.msl
@@ -1,9 +1,65 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  int k = 0;
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          {
+            int j = 0;
+            while(true) {
+              if ((j < 2)) {
+              } else {
+                break;
+              }
+              switch(j) {
+                case 0:
+                {
+                  j = (j + 2);
+                  continue;
+                }
+                case 1:
+                {
+                  switch(k) {
+                    case 0:
+                    {
+                      j = (j + 2);
+                      continue;
+                    }
+                    default:
+                    {
+                      break;
+                    }
+                  }
+                  break;
+                }
+                default:
+                {
+                  break;
+                }
+              }
+              j = (j + 2);
+              continue;
+            }
+          }
+          i = (i + 2);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 2);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.ir.msl b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.ir.msl
index cdbf128..a4f719e 100644
--- a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.ir.msl
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.ir.msl
@@ -1,9 +1,38 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  int j = 0;
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          switch(j) {
+            case 0:
+            {
+              i = (i + 2);
+              continue;
+            }
+            default:
+            {
+              break;
+            }
+          }
+          break;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 2);
+      continue;
+    }
+  }
+}
diff --git a/test/tint/loops/single_continue.wgsl.expected.ir.msl b/test/tint/loops/single_continue.wgsl.expected.ir.msl
index cdbf128..573c2b5 100644
--- a/test/tint/loops/single_continue.wgsl.expected.ir.msl
+++ b/test/tint/loops/single_continue.wgsl.expected.ir.msl
@@ -1,9 +1,27 @@
-SKIP: FAILED
+#include <metal_stdlib>
+using namespace metal;
 
-<dawn>/src/tint/lang/msl/writer/printer/printer.cc:247 internal compiler error: Switch() matched no cases. Type: tint::core::ir::Loop
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+kernel void tint_symbol() {
+  {
+    int i = 0;
+    while(true) {
+      if ((i < 2)) {
+      } else {
+        break;
+      }
+      switch(i) {
+        case 0:
+        {
+          i = (i + 1);
+          continue;
+        }
+        default:
+        {
+          break;
+        }
+      }
+      i = (i + 1);
+      continue;
+    }
+  }
+}