[ir] Emit `continue` statements when converting to a Program.

In `IRToProgram` the `continue` statements were never emitted. There
happened to be no tests which required continues to be emitted to be
correct. Add a test case which requires the continues and emit as
needed.

Change-Id: If67ca5c6b7fe8e5d8ccd76c1494137eb9ba13aef
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/243575
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/wgsl/ir_roundtrip_test.cc b/src/tint/lang/wgsl/ir_roundtrip_test.cc
index afe718d..a829ee7 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_test.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_test.cc
@@ -73,7 +73,6 @@
             result.err = ir_module.Failure().reason;
             return result;
         }
-
         result.ir_pre_raise = core::ir::Disassembler(ir_module.Get()).Plain();
 
         if (auto res = tint::wgsl::writer::Raise(ir_module.Get()); res != Success) {
@@ -2771,6 +2770,44 @@
 )");
 }
 
+TEST_F(IRToProgramRoundtripTest, Loop_WithRequiredContinues) {
+    RUN_TEST(R"(
+var<private> v : u32;
+
+var<private> v_1 : bool;
+
+var<private> v_2 : bool;
+
+fn f() {
+  let v_3 = v_1;
+  let v_4 = v_2;
+  loop {
+    var v_5 : u32;
+    if (v_3) {
+      break;
+    } else {
+      if (v_4) {
+        v_5 = 0u;
+        continue;
+      } else {
+        v_5 = 1u;
+      }
+      if (true) {
+        v_5 = 2u;
+        continue;
+      }
+      v_5 = 3u;
+      continue;
+    }
+
+    continuing {
+      v = v_5;
+    }
+  }
+}
+)");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // While
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index a0e8015..a941f19 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -367,7 +367,7 @@
             [&](const core::ir::Binary* i) { Binary(i); },                          //
             [&](const core::ir::BreakIf* i) { BreakIf(i); },                        //
             [&](const core::ir::Call* i) { Call(i); },                              //
-            [&](const core::ir::Continue*) {},                                      //
+            [&](const core::ir::Continue* c) { EmitContinue(c); },                  //
             [&](const core::ir::ExitIf*) {},                                        //
             [&](const core::ir::ExitLoop* i) { ExitLoop(i); },                      //
             [&](const core::ir::ExitSwitch* i) { ExitSwitch(i); },                  //
@@ -548,6 +548,15 @@
         Append(b.Break());
     }
 
+    void EmitContinue(const core::ir::Continue* c) {
+        auto* loop = c->Loop();
+        // No need to emit the continue as the last statement in loop as it's implicit
+        if (loop->Body()->Terminator() == c) {
+            return;
+        }
+        Append(b.Continue());
+    }
+
     void ExitLoop(const core::ir::ExitLoop*) { Append(b.Break()); }
 
     void BreakIf(const core::ir::BreakIf* i) { Append(b.BreakIf(Expr(i->Condition()))); }