[tint] Check uniformity for subgroup matrix variable declarations

Add a new type of node to represent a subgroup matrix variable
declaration, and special-case the diagnostic generation code.

Fixed: 403611388
Change-Id: I380832dda61499abb23debdf39422638088ff079
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/235657
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index 2bb5cdc..6570272 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -131,6 +131,7 @@
         kFunctionCallPointerArgumentResult,
         kFunctionCallReturnValue,
         kFunctionPointerParameterContents,
+        kSubgroupMatrixVariableDeclaration,
     };
 
     /// The type of the node.
@@ -1238,6 +1239,19 @@
                     }
                 } else {
                     node = cf;
+
+                    // Subgroup matrix variables cannot be declared in non-uniform control flow.
+                    if (ContainsSubgroupMatrix(sem_var->Type()->UnwrapRef())) {
+                        auto severity = sem_.DiagnosticSeverity(
+                            decl, wgsl::ChromiumDiagnosticRule::kSubgroupMatrixUniformity);
+                        if (severity != wgsl::DiagnosticSeverity::kOff) {
+                            // Create an extra node so that we can produce good diagnostics.
+                            node = CreateNode({NameFor(sem_var), "_decl"}, decl);
+                            node->type = Node::kSubgroupMatrixVariableDeclaration;
+                            node->AddEdge(cf);
+                            current_function_->RequiredToBeUniform(severity)->AddEdge(node);
+                        }
+                    }
                 }
                 current_function_->variables.Set(sem_var, node);
 
@@ -2101,6 +2115,19 @@
             return node->visited_from == function.RequiredToBeUniform(severity);
         });
 
+        // Special-case error for subgroup-matrix variable declarations, which are the only source
+        // of uniformity requirements that do not involve function calls.
+        if (cause->type == Node::kSubgroupMatrixVariableDeclaration) {
+            report(cause->ast->source,
+                   "variables that contain subgroup matrix types cannot be declared in non-uniform "
+                   "control flow",
+                   /* note */ false);
+
+            // Show the point at which control-flow depends on a non-uniform value.
+            ShowControlFlowDivergence(function, cause, source_node);
+            return;
+        }
+
         // The node will always have a corresponding call expression.
         auto* call = cause->ast->As<ast::CallExpression>();
         TINT_ASSERT(call);
diff --git a/src/tint/lang/wgsl/resolver/uniformity_test.cc b/src/tint/lang/wgsl/resolver/uniformity_test.cc
index 500dfda..0ffa2a6 100644
--- a/src/tint/lang/wgsl/resolver/uniformity_test.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity_test.cc
@@ -907,6 +907,128 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+/// Test subgroup matrix variable declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+TEST_F(UniformityAnalysisTest, SubgroupMatrixVarDecl_Pass) {
+    std::string src = R"(
+enable chromium_experimental_subgroup_matrix;
+
+@group(0) @binding(0) var<storage, read> ro : i32;
+
+fn foo() {
+  if (ro == 0) {
+    var sm : subgroup_matrix_result<f32, 8, 8>;
+  }
+}
+)";
+
+    RunTest(src, true);
+}
+
+TEST_F(UniformityAnalysisTest, SubgroupMatrixVarDecl_Fail) {
+    std::string src = R"(
+enable chromium_experimental_subgroup_matrix;
+
+@group(0) @binding(0) var<storage, read_write> rw : i32;
+
+fn foo() {
+  if (rw == 0) {
+    var sm : subgroup_matrix_result<f32, 8, 8>;
+  }
+}
+)";
+
+    RunTest(src, false);
+    EXPECT_EQ(
+        error_,
+        R"(test:8:5 error: variables that contain subgroup matrix types cannot be declared in non-uniform control flow
+    var sm : subgroup_matrix_result<f32, 8, 8>;
+    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+test:7:3 note: control flow depends on possibly non-uniform value
+  if (rw == 0) {
+  ^^
+
+test:7:7 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
+  if (rw == 0) {
+      ^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, SubgroupMatrixVarDecl_InStruct_Fail) {
+    std::string src = R"(
+enable chromium_experimental_subgroup_matrix;
+
+struct Inner {
+  u : u32,
+  sm : subgroup_matrix_result<f32, 8, 8>,
+}
+
+struct S {
+  u : u32,
+  inner : Inner,
+}
+
+@group(0) @binding(0) var<storage, read_write> rw : i32;
+
+fn foo() {
+  if (rw == 0) {
+    var sm : S;
+  }
+}
+)";
+
+    RunTest(src, false);
+    EXPECT_EQ(
+        error_,
+        R"(test:18:5 error: variables that contain subgroup matrix types cannot be declared in non-uniform control flow
+    var sm : S;
+    ^^^^^^^^^^
+
+test:17:3 note: control flow depends on possibly non-uniform value
+  if (rw == 0) {
+  ^^
+
+test:17:7 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
+  if (rw == 0) {
+      ^^
+)");
+}
+
+TEST_F(UniformityAnalysisTest, SubgroupMatrixVarDecl_InArray_Fail) {
+    std::string src = R"(
+enable chromium_experimental_subgroup_matrix;
+
+alias ArrayType = array<array<subgroup_matrix_result<f32, 8, 8>, 4>, 4>;
+
+@group(0) @binding(0) var<storage, read_write> rw : i32;
+
+fn foo() {
+  if (rw == 0) {
+    var sm : ArrayType;
+  }
+}
+)";
+
+    RunTest(src, false);
+    EXPECT_EQ(
+        error_,
+        R"(test:10:5 error: variables that contain subgroup matrix types cannot be declared in non-uniform control flow
+    var sm : ArrayType;
+    ^^^^^^^^^^^^^^^^^^
+
+test:9:3 note: control flow depends on possibly non-uniform value
+  if (rw == 0) {
+  ^^
+
+test:9:7 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
+  if (rw == 0) {
+      ^^
+)");
+}
+
+////////////////////////////////////////////////////////////////////////////////
 /// Test loop conditions and conditional break/continue statements.
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -10048,6 +10170,33 @@
     }
 }
 
+TEST_P(UniformityAnalysisDiagnosticFilterTest, Directive_SubgroupMatrixUniformity_VarDecl) {
+    auto& param = GetParam();
+    StringStream ss;
+    ss << "enable chromium_experimental_subgroup_matrix;\n"
+       << "diagnostic(" << param << ", chromium.subgroup_matrix_uniformity);" << R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+
+@group(0) @binding(1) var<storage, read_write> data : array<f32>;
+
+fn foo() {
+  if (non_uniform == 42) {
+    var sm : subgroup_matrix_left<f32, 8, 8>;
+  }
+}
+)";
+
+    RunTest(ss.str(), param != wgsl::DiagnosticSeverity::kError);
+
+    if (param == wgsl::DiagnosticSeverity::kOff) {
+        EXPECT_TRUE(error_.empty());
+    } else {
+        StringStream err;
+        err << ToStr(param) << ": variables that contain subgroup matrix types";
+        EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
+    }
+}
+
 TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction_DerivativeUniformity) {
     auto& param = GetParam();
     StringStream ss;