spirv-reader: ignore phi inputs coming from non-ordered blocks

Bug: tint:804
Change-Id: I789c05a31d869052036351b8c173ef8cd7191cc2
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/52841
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index b55ecd7..61dae65 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -4362,7 +4362,7 @@
           auto* pred_block_info = GetBlockInfo(pred_block_id);
           // The predecessor might not be in the block order at all, so we
           // need this guard.
-          if (pred_block_info) {
+          if (IsInBlockOrder(pred_block_info)) {
             // Record the assignment that needs to occur at the end
             // of the predecessor block.
             pred_block_info->phi_assignments.push_back({phi_id, value_id});
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index f0a2c97..2bfe745 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -766,6 +766,13 @@
     return where->second.get();
   }
 
+  /// Is the block, represented by info, in the structured block order?
+  /// @param info the block
+  /// @returns true if the block is in the structured block order.
+  bool IsInBlockOrder(const BlockInfo* info) const {
+    return info && info->pos != kInvalidBlockPos;
+  }
+
   /// Gets the local definition info for a result ID.
   /// @param id the SPIR-V ID of local definition.
   /// @returns the definition info for the given ID, if it exists, or nullptr
diff --git a/src/reader/spirv/function_var_test.cc b/src/reader/spirv/function_var_test.cc
index 8bacfad..dc474a0 100644
--- a/src/reader/spirv/function_var_test.cc
+++ b/src/reader/spirv/function_var_test.cc
@@ -2234,6 +2234,84 @@
   EXPECT_EQ(expect, got);
 }
 
+TEST_F(SpvParserFunctionVarTest,
+       EmitStatement_Phi_ValueFromBlockNotInBlockOrderIgnored) {
+  // From crbug.com/tint/804
+  const auto assembly = Preamble() + R"(
+     %float_42 = OpConstant %float 42.0
+     %cond = OpUndef %bool
+
+     %100 = OpFunction %void None %voidfn
+     %10 = OpLabel
+     OpBranch %30
+
+     ; unreachable
+     %20 = OpLabel
+     %499 = OpFAdd %float %float_42 %float_42
+     %500 = OpFAdd %float %499 %float_42
+     OpBranch %25
+
+     %25 = OpLabel
+     OpBranch %80
+
+
+     %30 = OpLabel
+     OpLoopMerge %90 %80 None
+     OpBranchConditional %cond %90 %40
+
+     %40 = OpLabel
+     OpBranch %90
+
+     %80 = OpLabel ; unreachable continue target
+                ; but "dominated" by %20 and %25
+     %81 = OpPhi %float %500 %25
+     OpBranch %30 ; backedge
+
+     %90 = OpLabel
+     OpReturn
+     OpFunctionEnd
+)";
+  auto p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+  auto fe = p->function_emitter(100);
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+
+  const auto* expected = R"(Loop{
+  If{
+    (
+      ScalarConstructor[not set]{false}
+    )
+    {
+      Break{}
+    }
+  }
+  Break{}
+  continuing {
+    VariableDeclStatement{
+      Variable{
+        x_81_phi_1
+        none
+        __f32
+      }
+    }
+    VariableDeclStatement{
+      VariableConst{
+        x_81
+        none
+        __f32
+        {
+          Identifier[not set]{x_81_phi_1}
+        }
+      }
+    }
+  }
+}
+Return{}
+)";
+  const auto got = ToString(p->builder(), fe.ast_body());
+  EXPECT_EQ(got, expected);
+}
+
 }  // namespace
 }  // namespace spirv
 }  // namespace reader