HLSL: workaround FXC error "continue cannot be used in a switch"

Added a new transform::RemoveContinueInSwitch that replaces continue
statements in switch cases with setting a bool variable, and checking if
the variable is set after the switch to continue.

Bug: tint:1080
Change-Id: I3c0a6c790e1bb612fac3f927a4bd5beb2d0d4ed1
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/84960
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index a2541bd..0d52704 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -471,6 +471,8 @@
     "transform/promote_initializers_to_const_var.h",
     "transform/promote_side_effects_to_decl.cc",
     "transform/promote_side_effects_to_decl.h",
+    "transform/remove_continue_in_switch.cc",
+    "transform/remove_continue_in_switch.h",
     "transform/remove_phonies.cc",
     "transform/remove_phonies.h",
     "transform/remove_unreachable_statements.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 0a3ce1c..30e2322 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -351,6 +351,8 @@
   transform/promote_side_effects_to_decl.h
   transform/remove_phonies.cc
   transform/remove_phonies.h
+  transform/remove_continue_in_switch.cc
+  transform/remove_continue_in_switch.h
   transform/remove_unreachable_statements.cc
   transform/remove_unreachable_statements.h
   transform/renamer.cc
@@ -1027,6 +1029,7 @@
       transform/num_workgroups_from_uniform_test.cc
       transform/promote_initializers_to_const_var_test.cc
       transform/promote_side_effects_to_decl_test.cc
+      transform/remove_continue_in_switch_test.cc
       transform/remove_phonies_test.cc
       transform/remove_unreachable_statements_test.cc
       transform/renamer_test.cc
diff --git a/src/tint/transform/remove_continue_in_switch.cc b/src/tint/transform/remove_continue_in_switch.cc
new file mode 100644
index 0000000..9ee05c0
--- /dev/null
+++ b/src/tint/transform/remove_continue_in_switch.cc
@@ -0,0 +1,145 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/remove_continue_in_switch.h"
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "src/tint/ast/continue_statement.h"
+#include "src/tint/ast/switch_statement.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/block_statement.h"
+#include "src/tint/sem/for_loop_statement.h"
+#include "src/tint/sem/loop_statement.h"
+#include "src/tint/sem/switch_statement.h"
+#include "src/tint/transform/utils/get_insertion_point.h"
+#include "src/tint/utils/map.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::transform::RemoveContinueInSwitch);
+
+namespace tint::transform {
+namespace {
+
+class State {
+ private:
+  CloneContext& ctx;
+  ProgramBuilder& b;
+  const sem::Info& sem;
+
+  // Map of switch statement to 'tint_continue' variable.
+  std::unordered_map<const ast::SwitchStatement*, Symbol>
+      switch_to_cont_var_name;
+
+  // If `cont` is within a switch statement within a loop, returns a pointer to
+  // that switch statement.
+  static const ast::SwitchStatement* GetParentSwitchInLoop(
+      const sem::Info& sem,
+      const ast::ContinueStatement* cont) {
+    // Find whether first parent is a switch or a loop
+    auto* sem_stmt = sem.Get(cont);
+    auto* sem_parent =
+        sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement,
+                                  sem::ForLoopStatement>();
+    if (!sem_parent) {
+      return nullptr;
+    }
+    return sem_parent->Declaration()->As<ast::SwitchStatement>();
+  }
+
+ public:
+  /// Constructor
+  /// @param ctx_in the context
+  explicit State(CloneContext& ctx_in)
+      : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
+
+  /// Returns true if this transform should be run for the given program
+  static bool ShouldRun(const Program* program) {
+    for (auto* node : program->ASTNodes().Objects()) {
+      auto* stmt = node->As<ast::ContinueStatement>();
+      if (!stmt) {
+        continue;
+      }
+      if (GetParentSwitchInLoop(program->Sem(), stmt)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /// Runs the transform
+  void Run() {
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+      auto* cont = node->As<ast::ContinueStatement>();
+      if (!cont) {
+        continue;
+      }
+
+      // If first parent is not a switch within a loop, skip
+      auto* switch_stmt = GetParentSwitchInLoop(sem, cont);
+      if (!switch_stmt) {
+        continue;
+      }
+
+      auto cont_var_name =
+          tint::utils::GetOrCreate(switch_to_cont_var_name, switch_stmt, [&]() {
+            // Create and insert 'var tint_continue : bool = false;' before the
+            // switch.
+            auto var_name = b.Symbols().New("tint_continue");
+            auto* decl = b.Decl(b.Var(var_name, b.ty.bool_(), b.Expr(false)));
+            auto ip = utils::GetInsertionPoint(ctx, switch_stmt);
+            ctx.InsertBefore(ip.first->Declaration()->statements, ip.second,
+                             decl);
+
+            // Create and insert 'if (tint_continue) { continue; }' after
+            // switch.
+            auto* if_stmt = b.If(b.Expr(var_name), b.Block(b.Continue()));
+            ctx.InsertAfter(ip.first->Declaration()->statements, ip.second,
+                            if_stmt);
+
+            // Return the new var name
+            return var_name;
+          });
+
+      // Replace 'continue;' with '{ tint_continue = true; break; }'
+      auto* new_stmt = b.Block(                   //
+          b.Assign(b.Expr(cont_var_name), true),  //
+          b.Break());
+
+      ctx.Replace(cont, new_stmt);
+    }
+
+    ctx.Clone();
+  }
+};
+
+}  // namespace
+
+RemoveContinueInSwitch::RemoveContinueInSwitch() = default;
+RemoveContinueInSwitch::~RemoveContinueInSwitch() = default;
+
+bool RemoveContinueInSwitch::ShouldRun(const Program* program,
+                                       const DataMap& /*data*/) const {
+  return State::ShouldRun(program);
+}
+
+void RemoveContinueInSwitch::Run(CloneContext& ctx,
+                                 const DataMap&,
+                                 DataMap&) const {
+  State state(ctx);
+  state.Run();
+}
+
+}  // namespace tint::transform
diff --git a/src/tint/transform/remove_continue_in_switch.h b/src/tint/transform/remove_continue_in_switch.h
new file mode 100644
index 0000000..f875660
--- /dev/null
+++ b/src/tint/transform/remove_continue_in_switch.h
@@ -0,0 +1,55 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
+#define SRC_TINT_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
+
+#include "src/tint/transform/transform.h"
+
+namespace tint::transform {
+
+/// This transform replaces continue statements in switch cases with setting a
+/// bool variable, and checking if the variable is set after the switch to
+/// continue. It is necessary to work around FXC "error X3708: continue cannot
+/// be used in a switch". See crbug.com/tint/1080.
+class RemoveContinueInSwitch
+    : public Castable<RemoveContinueInSwitch, Transform> {
+ public:
+  /// Constructor
+  RemoveContinueInSwitch();
+
+  /// Destructor
+  ~RemoveContinueInSwitch() override;
+
+ protected:
+  /// @param program the program to inspect
+  /// @param data optional extra transform-specific input data
+  /// @returns true if this transform should be run for the given program
+  bool ShouldRun(const Program* program,
+                 const DataMap& data = {}) const override;
+
+  /// Runs the transform using the CloneContext built for transforming a
+  /// program. Run() is responsible for calling Clone() on the CloneContext.
+  /// @param ctx the CloneContext primed with the input program and
+  /// ProgramBuilder
+  /// @param inputs optional extra transform-specific input data
+  /// @param outputs optional extra transform-specific output data
+  void Run(CloneContext& ctx,
+           const DataMap& inputs,
+           DataMap& outputs) const override;
+};
+
+}  // namespace tint::transform
+
+#endif  // SRC_TINT_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
diff --git a/src/tint/transform/remove_continue_in_switch_test.cc b/src/tint/transform/remove_continue_in_switch_test.cc
new file mode 100644
index 0000000..cd485b0
--- /dev/null
+++ b/src/tint/transform/remove_continue_in_switch_test.cc
@@ -0,0 +1,565 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/transform/remove_continue_in_switch.h"
+#include "src/tint/transform/test_helper.h"
+
+namespace tint {
+namespace transform {
+namespace {
+
+using RemoveContinueInSwitchTest = TransformTest;
+
+TEST_F(RemoveContinueInSwitchTest, ShouldRun_True) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  loop {
+    switch(i) {
+      case 0: {
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    break;
+  }
+}
+)";
+
+  EXPECT_TRUE(ShouldRun<RemoveContinueInSwitch>(src));
+}
+
+TEST_F(RemoveContinueInSwitchTest, ShouldRunEmptyModule_False) {
+  auto* src = "";
+
+  EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
+}
+
+TEST_F(RemoveContinueInSwitchTest, ShouldRunContinueNotInSwitch_False) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  loop {
+    switch(i) {
+      case 0: {
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+
+    if (true) {
+      continue;
+    }
+    break;
+  }
+}
+)";
+
+  EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
+}
+
+TEST_F(RemoveContinueInSwitchTest, ShouldRunContinueInLoopInSwitch_False) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  switch(i) {
+    case 0: {
+      loop {
+        if (true) {
+          continue;
+        }
+        break;
+      }
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+}
+)";
+
+  EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
+}
+
+TEST_F(RemoveContinueInSwitchTest, EmptyModule) {
+  auto* src = "";
+  auto* expect = src;
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, SingleContinue) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    switch(i) {
+      case 0: {
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    let marker2 = 0;
+    break;
+
+    continuing {
+      let marker3 = 0;
+    }
+  }
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    var tint_continue : bool = false;
+    switch(i) {
+      case 0: {
+        {
+          tint_continue = true;
+          break;
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    if (tint_continue) {
+      continue;
+    }
+    let marker2 = 0;
+    break;
+
+    continuing {
+      let marker3 = 0;
+    }
+  }
+}
+)";
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, MultipleContinues) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    switch(i) {
+      case 0: {
+        continue;
+        break;
+      }
+      case 1: {
+        continue;
+        break;
+      }
+      case 2: {
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    let marker2 = 0;
+    break;
+
+    continuing {
+      let marker3 = 0;
+    }
+  }
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    var tint_continue : bool = false;
+    switch(i) {
+      case 0: {
+        {
+          tint_continue = true;
+          break;
+        }
+        break;
+      }
+      case 1: {
+        {
+          tint_continue = true;
+          break;
+        }
+        break;
+      }
+      case 2: {
+        {
+          tint_continue = true;
+          break;
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    if (tint_continue) {
+      continue;
+    }
+    let marker2 = 0;
+    break;
+
+    continuing {
+      let marker3 = 0;
+    }
+  }
+}
+)";
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, MultipleSwitch) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    switch(i) {
+      case 0: {
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    let marker2 = 0;
+
+    let marker3 = 0;
+    switch(i) {
+      case 0: {
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    let marker4 = 0;
+
+    break;
+  }
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    var tint_continue : bool = false;
+    switch(i) {
+      case 0: {
+        {
+          tint_continue = true;
+          break;
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    if (tint_continue) {
+      continue;
+    }
+    let marker2 = 0;
+    let marker3 = 0;
+    var tint_continue_1 : bool = false;
+    switch(i) {
+      case 0: {
+        {
+          tint_continue_1 = true;
+          break;
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    if (tint_continue_1) {
+      continue;
+    }
+    let marker4 = 0;
+    break;
+  }
+}
+)";
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, NestedLoopSwitch) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    switch(i) {
+      case 0: {
+        var j = 0;
+        loop {
+          let marker3 = 0;
+          switch(j) {
+            case 0: {
+              continue;
+              break;
+            }
+            default: {
+              break;
+            }
+          }
+          let marker4 = 0;
+          break;
+        }
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    let marker2 = 0;
+    break;
+  }
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  var i = 0;
+  loop {
+    let marker1 = 0;
+    var tint_continue_1 : bool = false;
+    switch(i) {
+      case 0: {
+        var j = 0;
+        loop {
+          let marker3 = 0;
+          var tint_continue : bool = false;
+          switch(j) {
+            case 0: {
+              {
+                tint_continue = true;
+                break;
+              }
+              break;
+            }
+            default: {
+              break;
+            }
+          }
+          if (tint_continue) {
+            continue;
+          }
+          let marker4 = 0;
+          break;
+        }
+        {
+          tint_continue_1 = true;
+          break;
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    if (tint_continue_1) {
+      continue;
+    }
+    let marker2 = 0;
+    break;
+  }
+}
+)";
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, ExtraScopes) {
+  auto* src = R"(
+fn f() {
+  var i = 0;
+  var a = true;
+  var b = true;
+  var c = true;
+  var d = true;
+  loop {
+    if (a) {
+      if (b) {
+        let marker1 = 0;
+        switch(i) {
+          case 0: {
+            if (c) {
+              if (d) {
+                continue;
+              }
+            }
+            break;
+          }
+          default: {
+            break;
+          }
+        }
+        let marker2 = 0;
+        break;
+      }
+    }
+  }
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  var i = 0;
+  var a = true;
+  var b = true;
+  var c = true;
+  var d = true;
+  loop {
+    if (a) {
+      if (b) {
+        let marker1 = 0;
+        var tint_continue : bool = false;
+        switch(i) {
+          case 0: {
+            if (c) {
+              if (d) {
+                {
+                  tint_continue = true;
+                  break;
+                }
+              }
+            }
+            break;
+          }
+          default: {
+            break;
+          }
+        }
+        if (tint_continue) {
+          continue;
+        }
+        let marker2 = 0;
+        break;
+      }
+    }
+  }
+}
+)";
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, ForLoop) {
+  auto* src = R"(
+fn f() {
+  for (var i = 0; i < 4; i = i + 1) {
+    let marker1 = 0;
+    switch(i) {
+      case 0: {
+        continue;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    let marker2 = 0;
+    break;
+  }
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  for(var i = 0; (i < 4); i = (i + 1)) {
+    let marker1 = 0;
+    var tint_continue : bool = false;
+    switch(i) {
+      case 0: {
+        {
+          tint_continue = true;
+          break;
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+    if (tint_continue) {
+      continue;
+    }
+    let marker2 = 0;
+    break;
+  }
+}
+)";
+
+  DataMap data;
+  auto got = Run<RemoveContinueInSwitch>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+}  // namespace
+}  // namespace transform
+}  // namespace tint
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index e384156..9ed948d 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -59,6 +59,7 @@
 #include "src/tint/transform/num_workgroups_from_uniform.h"
 #include "src/tint/transform/promote_initializers_to_const_var.h"
 #include "src/tint/transform/promote_side_effects_to_decl.h"
+#include "src/tint/transform/remove_continue_in_switch.h"
 #include "src/tint/transform/remove_phonies.h"
 #include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/transform/unshadow.h"
@@ -210,6 +211,8 @@
   manager.Add<transform::CalculateArrayLength>();
   manager.Add<transform::PromoteInitializersToConstVar>();
 
+  manager.Add<transform::RemoveContinueInSwitch>();
+
   manager.Add<transform::AddEmptyEntryPoint>();
 
   data.Add<transform::CanonicalizeEntryPointIO::Config>(
diff --git a/test/tint/BUILD.gn b/test/tint/BUILD.gn
index 6bdd527..3588b08 100644
--- a/test/tint/BUILD.gn
+++ b/test/tint/BUILD.gn
@@ -329,6 +329,7 @@
     "../../src/tint/transform/num_workgroups_from_uniform_test.cc",
     "../../src/tint/transform/promote_initializers_to_const_var_test.cc",
     "../../src/tint/transform/promote_side_effects_to_decl_test.cc",
+    "../../src/tint/transform/remove_continue_in_switch_test.cc",
     "../../src/tint/transform/remove_phonies_test.cc",
     "../../src/tint/transform/remove_unreachable_statements_test.cc",
     "../../src/tint/transform/renamer_test.cc",
diff --git a/test/tint/loops/continue_in_switch.wgsl.expected.hlsl b/test/tint/loops/continue_in_switch.wgsl.expected.hlsl
index 773a4ce..3aa81e3 100644
--- a/test/tint/loops/continue_in_switch.wgsl.expected.hlsl
+++ b/test/tint/loops/continue_in_switch.wgsl.expected.hlsl
@@ -1,20 +1,24 @@
-SKIP: FAILED
-
 [numthreads(1, 1, 1)]
 void f() {
   {
     [loop] for(int i = 0; (i < 4); i = (i + 1)) {
+      bool tint_continue = false;
       switch(i) {
         case 0: {
-          continue;
+          {
+            tint_continue = true;
+            break;
+          }
           break;
         }
         default: {
           break;
         }
       }
+      if (tint_continue) {
+        continue;
+      }
     }
   }
   return;
 }
-C:\src\tint\test\Shader@0x000001A817AB3700(7,11-19): error X3708: continue cannot be used in a switch
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.spvasm.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.spvasm.expected.hlsl
deleted file mode 100644
index 8be27ab..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.spvasm.expected.hlsl
+++ /dev/null
@@ -1,122 +0,0 @@
-SKIP: FAILED
-
-warning: code is unreachable
-cbuffer cbuffer_x_6 : register(b0, space0) {
-  uint4 x_6[1];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void main_1() {
-  int data[10] = (int[10])0;
-  int x_40 = 0;
-  int x_40_phi = 0;
-  int x_11_phi = 0;
-  const int x_7 = data[1];
-  const int x_10 = ((1 < x_7) ? 2 : 1);
-  x_40_phi = 1;
-  x_11_phi = x_10;
-  [loop] while (true) {
-    int x_54 = 0;
-    int x_41 = 0;
-    int x_41_phi = 0;
-    x_40 = x_40_phi;
-    const int x_11 = x_11_phi;
-    if ((x_11 < 3)) {
-    } else {
-      break;
-    }
-    int x_54_phi = 0;
-    const int x_8 = (x_11 + 1);
-    const float x_47 = asfloat(x_6[0].x);
-    x_54_phi = x_40;
-    switch(int(x_47)) {
-      case 78: {
-        x_GLF_color = float4(1.0f, 1.0f, 1.0f, 1.0f);
-        /* fallthrough */
-        {
-          x_54_phi = asint((x_40 + asint(1)));
-          /* fallthrough */
-        }
-        {
-          x_54 = x_54_phi;
-          x_41_phi = x_54;
-          {
-            x_41 = x_41_phi;
-            x_40_phi = x_41;
-            x_11_phi = x_8;
-          }
-          continue;
-        }
-        break;
-      }
-      case 19: {
-        x_54_phi = asint((x_40 + asint(1)));
-        /* fallthrough */
-        {
-          x_54 = x_54_phi;
-          x_41_phi = x_54;
-          {
-            x_41 = x_41_phi;
-            x_40_phi = x_41;
-            x_11_phi = x_8;
-          }
-          continue;
-        }
-        break;
-      }
-      case 23:
-      case 38: {
-        x_54 = x_54_phi;
-        x_41_phi = x_54;
-        {
-          x_41 = x_41_phi;
-          x_40_phi = x_41;
-          x_11_phi = x_8;
-        }
-        continue;
-        break;
-      }
-      default: {
-        x_41_phi = x_40;
-        {
-          x_41 = x_41_phi;
-          x_40_phi = x_41;
-          x_11_phi = x_8;
-        }
-        continue;
-        break;
-      }
-    }
-    x_41_phi = 0;
-    {
-      x_41 = x_41_phi;
-      x_40_phi = x_41;
-      x_11_phi = x_8;
-    }
-  }
-  data[x_40] = 1;
-  x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
-  return;
-}
-
-struct main_out {
-  float4 x_GLF_color_1;
-};
-struct tint_symbol {
-  float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
-  main_1();
-  const main_out tint_symbol_2 = {x_GLF_color};
-  return tint_symbol_2;
-}
-
-tint_symbol main() {
-  const main_out inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
-  return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000022C8EAC8720(45,11-19): error X3708: continue cannot be used in a switch
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.wgsl.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.wgsl.expected.hlsl
deleted file mode 100644
index 58fea7f..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.wgsl.expected.hlsl
+++ /dev/null
@@ -1,125 +0,0 @@
-SKIP: FAILED
-
-vk-gl-cts/graphicsfuzz/call-if-while-switch/0-opt.wgsl:52:5 warning: code is unreachable
-    x_41_phi = 0;
-    ^^^^^^^^
-
-cbuffer cbuffer_x_6 : register(b0, space0) {
-  uint4 x_6[1];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void main_1() {
-  int data[10] = (int[10])0;
-  int x_40 = 0;
-  int x_40_phi = 0;
-  int x_11_phi = 0;
-  const int x_7 = data[1];
-  const int x_10 = ((1 < x_7) ? 2 : 1);
-  x_40_phi = 1;
-  x_11_phi = x_10;
-  [loop] while (true) {
-    int x_54 = 0;
-    int x_41 = 0;
-    int x_41_phi = 0;
-    x_40 = x_40_phi;
-    const int x_11 = x_11_phi;
-    if ((x_11 < 3)) {
-    } else {
-      break;
-    }
-    int x_54_phi = 0;
-    const int x_8 = (x_11 + 1);
-    const float x_47 = asfloat(x_6[0].x);
-    x_54_phi = x_40;
-    switch(int(x_47)) {
-      case 78: {
-        x_GLF_color = float4(1.0f, 1.0f, 1.0f, 1.0f);
-        /* fallthrough */
-        {
-          x_54_phi = asint((x_40 + asint(1)));
-          /* fallthrough */
-        }
-        {
-          x_54 = x_54_phi;
-          x_41_phi = x_54;
-          {
-            x_41 = x_41_phi;
-            x_40_phi = x_41;
-            x_11_phi = x_8;
-          }
-          continue;
-        }
-        break;
-      }
-      case 19: {
-        x_54_phi = asint((x_40 + asint(1)));
-        /* fallthrough */
-        {
-          x_54 = x_54_phi;
-          x_41_phi = x_54;
-          {
-            x_41 = x_41_phi;
-            x_40_phi = x_41;
-            x_11_phi = x_8;
-          }
-          continue;
-        }
-        break;
-      }
-      case 23:
-      case 38: {
-        x_54 = x_54_phi;
-        x_41_phi = x_54;
-        {
-          x_41 = x_41_phi;
-          x_40_phi = x_41;
-          x_11_phi = x_8;
-        }
-        continue;
-        break;
-      }
-      default: {
-        x_41_phi = x_40;
-        {
-          x_41 = x_41_phi;
-          x_40_phi = x_41;
-          x_11_phi = x_8;
-        }
-        continue;
-        break;
-      }
-    }
-    x_41_phi = 0;
-    {
-      x_41 = x_41_phi;
-      x_40_phi = x_41;
-      x_11_phi = x_8;
-    }
-  }
-  data[x_40] = 1;
-  x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
-  return;
-}
-
-struct main_out {
-  float4 x_GLF_color_1;
-};
-struct tint_symbol {
-  float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
-  main_1();
-  const main_out tint_symbol_2 = {x_GLF_color};
-  return tint_symbol_2;
-}
-
-tint_symbol main() {
-  const main_out inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
-  return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000025D82F36130(45,11-19): error X3708: continue cannot be used in a switch
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/cov-x86-isel-lowering-negative-left-shift/0-opt.spvasm.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/cov-x86-isel-lowering-negative-left-shift/0-opt.spvasm.expected.hlsl
deleted file mode 100644
index dafcc86..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/cov-x86-isel-lowering-negative-left-shift/0-opt.spvasm.expected.hlsl
+++ /dev/null
@@ -1,124 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_6 : register(b1, space0) {
-  uint4 x_6[3];
-};
-cbuffer cbuffer_x_9 : register(b0, space0) {
-  uint4 x_9[4];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void main_1() {
-  float A[2] = (float[2])0;
-  int i = 0;
-  int j = 0;
-  bool x_101 = false;
-  bool x_102_phi = false;
-  const float x_39 = asfloat(x_6[1].x);
-  A[0] = x_39;
-  const float x_42 = asfloat(x_6[1].x);
-  A[1] = x_42;
-  const uint scalar_offset = ((16u * uint(0))) / 4;
-  const int x_45 = asint(x_9[scalar_offset / 4][scalar_offset % 4]);
-  i = x_45;
-  [loop] while (true) {
-    const int x_50 = i;
-    const int x_52 = asint(x_9[3].x);
-    if ((x_50 < x_52)) {
-    } else {
-      break;
-    }
-    const uint scalar_offset_1 = ((16u * uint(0))) / 4;
-    const int x_56 = asint(x_9[scalar_offset_1 / 4][scalar_offset_1 % 4]);
-    j = x_56;
-    [loop] while (true) {
-      const int x_61 = j;
-      const int x_63 = asint(x_9[2].x);
-      if ((x_61 < x_63)) {
-      } else {
-        break;
-      }
-      switch(j) {
-        case 1: {
-          const int x_78 = i;
-          const uint scalar_offset_2 = ((16u * uint(0))) / 4;
-          const float x_80 = asfloat(x_6[scalar_offset_2 / 4][scalar_offset_2 % 4]);
-          A[x_78] = x_80;
-          break;
-        }
-        case 0: {
-          if ((-2147483648 < i)) {
-            {
-              j = (j + 1);
-            }
-            continue;
-          }
-          const int x_74 = i;
-          const float x_76 = asfloat(x_6[2].x);
-          A[x_74] = x_76;
-          break;
-        }
-        default: {
-          break;
-        }
-      }
-      {
-        j = (j + 1);
-      }
-    }
-    {
-      i = (i + 1);
-    }
-  }
-  const uint scalar_offset_3 = ((16u * uint(0))) / 4;
-  const int x_87 = asint(x_9[scalar_offset_3 / 4][scalar_offset_3 % 4]);
-  const float x_89 = A[x_87];
-  const uint scalar_offset_4 = ((16u * uint(0))) / 4;
-  const float x_91 = asfloat(x_6[scalar_offset_4 / 4][scalar_offset_4 % 4]);
-  const bool x_92 = (x_89 == x_91);
-  x_102_phi = x_92;
-  if (x_92) {
-    const int x_96 = asint(x_9[1].x);
-    const float x_98 = A[x_96];
-    const uint scalar_offset_5 = ((16u * uint(0))) / 4;
-    const float x_100 = asfloat(x_6[scalar_offset_5 / 4][scalar_offset_5 % 4]);
-    x_101 = (x_98 == x_100);
-    x_102_phi = x_101;
-  }
-  if (x_102_phi) {
-    const int x_107 = asint(x_9[1].x);
-    const uint scalar_offset_6 = ((16u * uint(0))) / 4;
-    const int x_110 = asint(x_9[scalar_offset_6 / 4][scalar_offset_6 % 4]);
-    const uint scalar_offset_7 = ((16u * uint(0))) / 4;
-    const int x_113 = asint(x_9[scalar_offset_7 / 4][scalar_offset_7 % 4]);
-    const int x_116 = asint(x_9[1].x);
-    x_GLF_color = float4(float(x_107), float(x_110), float(x_113), float(x_116));
-  } else {
-    const int x_120 = asint(x_9[1].x);
-    const float x_121 = float(x_120);
-    x_GLF_color = float4(x_121, x_121, x_121, x_121);
-  }
-  return;
-}
-
-struct main_out {
-  float4 x_GLF_color_1;
-};
-struct tint_symbol {
-  float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
-  main_1();
-  const main_out tint_symbol_3 = {x_GLF_color};
-  return tint_symbol_3;
-}
-
-tint_symbol main() {
-  const main_out inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
-  return wrapper_result;
-}
-C:\src\tint\test\Shader@0x000001CAF72F14F0(52,13-21): error X3708: continue cannot be used in a switch
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/cov-x86-isel-lowering-negative-left-shift/0-opt.wgsl.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/cov-x86-isel-lowering-negative-left-shift/0-opt.wgsl.expected.hlsl
deleted file mode 100644
index 4843bc4..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/cov-x86-isel-lowering-negative-left-shift/0-opt.wgsl.expected.hlsl
+++ /dev/null
@@ -1,124 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_6 : register(b1, space0) {
-  uint4 x_6[3];
-};
-cbuffer cbuffer_x_9 : register(b0, space0) {
-  uint4 x_9[4];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void main_1() {
-  float A[2] = (float[2])0;
-  int i = 0;
-  int j = 0;
-  bool x_101 = false;
-  bool x_102_phi = false;
-  const float x_39 = asfloat(x_6[1].x);
-  A[0] = x_39;
-  const float x_42 = asfloat(x_6[1].x);
-  A[1] = x_42;
-  const uint scalar_offset = ((16u * uint(0))) / 4;
-  const int x_45 = asint(x_9[scalar_offset / 4][scalar_offset % 4]);
-  i = x_45;
-  [loop] while (true) {
-    const int x_50 = i;
-    const int x_52 = asint(x_9[3].x);
-    if ((x_50 < x_52)) {
-    } else {
-      break;
-    }
-    const uint scalar_offset_1 = ((16u * uint(0))) / 4;
-    const int x_56 = asint(x_9[scalar_offset_1 / 4][scalar_offset_1 % 4]);
-    j = x_56;
-    [loop] while (true) {
-      const int x_61 = j;
-      const int x_63 = asint(x_9[2].x);
-      if ((x_61 < x_63)) {
-      } else {
-        break;
-      }
-      switch(j) {
-        case 1: {
-          const int x_78 = i;
-          const uint scalar_offset_2 = ((16u * uint(0))) / 4;
-          const float x_80 = asfloat(x_6[scalar_offset_2 / 4][scalar_offset_2 % 4]);
-          A[x_78] = x_80;
-          break;
-        }
-        case 0: {
-          if ((-2147483648 < i)) {
-            {
-              j = (j + 1);
-            }
-            continue;
-          }
-          const int x_74 = i;
-          const float x_76 = asfloat(x_6[2].x);
-          A[x_74] = x_76;
-          break;
-        }
-        default: {
-          break;
-        }
-      }
-      {
-        j = (j + 1);
-      }
-    }
-    {
-      i = (i + 1);
-    }
-  }
-  const uint scalar_offset_3 = ((16u * uint(0))) / 4;
-  const int x_87 = asint(x_9[scalar_offset_3 / 4][scalar_offset_3 % 4]);
-  const float x_89 = A[x_87];
-  const uint scalar_offset_4 = ((16u * uint(0))) / 4;
-  const float x_91 = asfloat(x_6[scalar_offset_4 / 4][scalar_offset_4 % 4]);
-  const bool x_92 = (x_89 == x_91);
-  x_102_phi = x_92;
-  if (x_92) {
-    const int x_96 = asint(x_9[1].x);
-    const float x_98 = A[x_96];
-    const uint scalar_offset_5 = ((16u * uint(0))) / 4;
-    const float x_100 = asfloat(x_6[scalar_offset_5 / 4][scalar_offset_5 % 4]);
-    x_101 = (x_98 == x_100);
-    x_102_phi = x_101;
-  }
-  if (x_102_phi) {
-    const int x_107 = asint(x_9[1].x);
-    const uint scalar_offset_6 = ((16u * uint(0))) / 4;
-    const int x_110 = asint(x_9[scalar_offset_6 / 4][scalar_offset_6 % 4]);
-    const uint scalar_offset_7 = ((16u * uint(0))) / 4;
-    const int x_113 = asint(x_9[scalar_offset_7 / 4][scalar_offset_7 % 4]);
-    const int x_116 = asint(x_9[1].x);
-    x_GLF_color = float4(float(x_107), float(x_110), float(x_113), float(x_116));
-  } else {
-    const int x_120 = asint(x_9[1].x);
-    const float x_121 = float(x_120);
-    x_GLF_color = float4(x_121, x_121, x_121, x_121);
-  }
-  return;
-}
-
-struct main_out {
-  float4 x_GLF_color_1;
-};
-struct tint_symbol {
-  float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
-  main_1();
-  const main_out tint_symbol_3 = {x_GLF_color};
-  return tint_symbol_3;
-}
-
-tint_symbol main() {
-  const main_out inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
-  return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000027536C22E40(52,13-21): error X3708: continue cannot be used in a switch
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/switch-loop-switch-if/0-opt.spvasm.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/switch-loop-switch-if/0-opt.spvasm.expected.hlsl
deleted file mode 100644
index 65bba35..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/switch-loop-switch-if/0-opt.spvasm.expected.hlsl
+++ /dev/null
@@ -1,86 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_6 : register(b0, space0) {
-  uint4 x_6[1];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void main_1() {
-  int i = 0;
-  const float x_51 = asfloat(x_6[0].x);
-  i = int(x_51);
-  switch(i) {
-    case 0: {
-      [loop] while (true) {
-        i = (i + 1);
-        switch(i) {
-          case 2: {
-            i = (i + 5);
-            break;
-          }
-          case 1: {
-            {
-              if ((i > 200)) {
-              } else {
-                break;
-              }
-            }
-            continue;
-            break;
-          }
-          default: {
-            i = (i + 7);
-            break;
-          }
-        }
-        {
-          if ((i > 200)) {
-          } else {
-            break;
-          }
-        }
-      }
-      if ((i > 100)) {
-        i = (i - 2);
-        break;
-      }
-      /* fallthrough */
-      {
-        i = (i - 3);
-      }
-      break;
-    }
-    default: {
-      i = (i - 3);
-      break;
-    }
-  }
-  if ((i == -2)) {
-    x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
-  } else {
-    x_GLF_color = float4(0.0f, 0.0f, 0.0f, 1.0f);
-  }
-  return;
-}
-
-struct main_out {
-  float4 x_GLF_color_1;
-};
-struct tint_symbol {
-  float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
-  main_1();
-  const main_out tint_symbol_2 = {x_GLF_color};
-  return tint_symbol_2;
-}
-
-tint_symbol main() {
-  const main_out inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
-  return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000013B8CBD6FE0(26,13-21): error X3708: continue cannot be used in a switch
-
diff --git a/test/tint/vk-gl-cts/graphicsfuzz/switch-loop-switch-if/0-opt.wgsl.expected.hlsl b/test/tint/vk-gl-cts/graphicsfuzz/switch-loop-switch-if/0-opt.wgsl.expected.hlsl
deleted file mode 100644
index 7516688..0000000
--- a/test/tint/vk-gl-cts/graphicsfuzz/switch-loop-switch-if/0-opt.wgsl.expected.hlsl
+++ /dev/null
@@ -1,86 +0,0 @@
-SKIP: FAILED
-
-cbuffer cbuffer_x_6 : register(b0, space0) {
-  uint4 x_6[1];
-};
-static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
-
-void main_1() {
-  int i = 0;
-  const float x_51 = asfloat(x_6[0].x);
-  i = int(x_51);
-  switch(i) {
-    case 0: {
-      [loop] while (true) {
-        i = (i + 1);
-        switch(i) {
-          case 2: {
-            i = (i + 5);
-            break;
-          }
-          case 1: {
-            {
-              if ((i > 200)) {
-              } else {
-                break;
-              }
-            }
-            continue;
-            break;
-          }
-          default: {
-            i = (i + 7);
-            break;
-          }
-        }
-        {
-          if ((i > 200)) {
-          } else {
-            break;
-          }
-        }
-      }
-      if ((i > 100)) {
-        i = (i - 2);
-        break;
-      }
-      /* fallthrough */
-      {
-        i = (i - 3);
-      }
-      break;
-    }
-    default: {
-      i = (i - 3);
-      break;
-    }
-  }
-  if ((i == -2)) {
-    x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
-  } else {
-    x_GLF_color = float4(0.0f, 0.0f, 0.0f, 1.0f);
-  }
-  return;
-}
-
-struct main_out {
-  float4 x_GLF_color_1;
-};
-struct tint_symbol {
-  float4 x_GLF_color_1 : SV_Target0;
-};
-
-main_out main_inner() {
-  main_1();
-  const main_out tint_symbol_2 = {x_GLF_color};
-  return tint_symbol_2;
-}
-
-tint_symbol main() {
-  const main_out inner_result = main_inner();
-  tint_symbol wrapper_result = (tint_symbol)0;
-  wrapper_result.x_GLF_color_1 = inner_result.x_GLF_color_1;
-  return wrapper_result;
-}
-C:\src\tint\test\Shader@0x0000019C85DE9DB0(26,13-21): error X3708: continue cannot be used in a switch
-