[ir] Fix loop condition matching in IR->WGSL

When there were two consecutive if instruction blocks that match the
loop condition pattern, the first was being dropped, leading to
unvisited nodes in the Resolver.

Bug: 351700183
Change-Id: I63e30f72cb648515198a8072b12b92b58bb6527b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/197355
Commit-Queue: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Auto-Submit: James Price <jrprice@google.com>
diff --git a/src/tint/lang/wgsl/ir_roundtrip_test.cc b/src/tint/lang/wgsl/ir_roundtrip_test.cc
index 7afcb96..278e8a6 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_test.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_test.cc
@@ -2813,6 +2813,20 @@
 )");
 }
 
+// Test case for crbug.com/351700183.
+TEST_F(IRToProgramRoundtripTest, While_ConditionAndBreak) {
+    RUN_TEST(R"(
+fn f() {
+  while(true) {
+    if (false) {
+    } else {
+      break;
+    }
+  }
+}
+)");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Loop
 ////////////////////////////////////////////////////////////////////////////////
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 12afe90..265b787 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
@@ -432,7 +432,7 @@
         {
             TINT_SCOPED_ASSIGNMENT(statements_, &body_stmts);
             for (auto* inst : *l->Body()) {
-                if (body_stmts.IsEmpty()) {
+                if (body_stmts.IsEmpty() && !cond) {
                     if (auto* if_ = inst->As<core::ir::If>()) {
                         if (if_->Results().IsEmpty() &&                          //
                             if_->True()->Length() == 1 &&                        //
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index d9d55fc..2a5bed4 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -2398,6 +2398,75 @@
 )");
 }
 
+TEST_F(IRToProgramTest, While_BreakAfterStatement) {
+    auto* fn = b.Function("f", ty.void_());
+
+    b.Append(fn->Block(), [&] {
+        auto* loop = b.Loop();
+
+        b.Append(loop->Body(), [&] {
+            auto* let = b.Let("cond", true);
+            auto* cond = b.If(let);
+            b.Append(cond->True(), [&] { b.ExitIf(cond); });
+            b.Append(cond->False(), [&] { b.ExitLoop(loop); });
+
+            b.ExitLoop(loop);
+        });
+
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f() {
+  loop {
+    let cond = true;
+    if (cond) {
+    } else {
+      break;
+    }
+    break;
+  }
+}
+)");
+}
+
+// Test that only the first "if continue then break" instruction is treated as the loop condition.
+// See crbug.com/351700183.
+TEST_F(IRToProgramTest, While_IfBreakInFalse) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* cond = b.FunctionParam("cond", ty.bool_());
+    fn->SetParams({cond});
+
+    b.Append(fn->Block(), [&] {
+        auto* loop = b.Loop();
+
+        b.Append(loop->Body(), [&] {
+            auto* if1 = b.If(true);
+            b.Append(if1->True(), [&] { b.ExitIf(if1); });
+            b.Append(if1->False(), [&] { b.ExitLoop(loop); });
+
+            auto* if2 = b.If(cond);
+            b.Append(if2->True(), [&] { b.ExitIf(if2); });
+            b.Append(if2->False(), [&] { b.ExitLoop(loop); });
+
+            b.Continue(loop);
+        });
+
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(cond : bool) {
+  while(true) {
+    if (cond) {
+    } else {
+      break;
+    }
+  }
+}
+)");
+}
+
 TEST_F(IRToProgramTest, While_IfReturn) {
     auto* fn = b.Function("f", ty.void_());
     auto* cond = b.FunctionParam("cond", ty.bool_());