[msl-writer] Emit zero values for private, function and output vars.

This CL updates the MSL writer to emit the needed zero initializers for
Private, Function and Output variables.

Bug: tint:172
Change-Id: I73b1c3bb4c87a8ec7b1fb9d17a35e907c9a42095
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28943
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index b3efd73..45773b9 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -819,6 +819,16 @@
     out_ << "0u";
   } else if (type->IsVector()) {
     return EmitZeroValue(type->AsVector()->type());
+  } else if (type->IsMatrix()) {
+    return EmitZeroValue(type->AsMatrix()->type());
+  } else if (type->IsArray()) {
+    out_ << "{";
+    if (!EmitZeroValue(type->AsArray()->type())) {
+      return false;
+    }
+    out_ << "}";
+  } else if (type->IsStruct()) {
+    out_ << "{}";
   } else {
     error_ = "Invalid type for zero emission: " + type->type_name();
     return false;
@@ -1805,10 +1815,19 @@
     out_ << " " << var->name();
   }
 
-  if (!skip_constructor && var->constructor() != nullptr) {
+  if (!skip_constructor) {
     out_ << " = ";
-    if (!EmitExpression(var->constructor())) {
-      return false;
+    if (var->constructor() != nullptr) {
+      if (!EmitExpression(var->constructor())) {
+        return false;
+      }
+    } else if (var->storage_class() == ast::StorageClass::kPrivate ||
+               var->storage_class() == ast::StorageClass::kFunction ||
+               var->storage_class() == ast::StorageClass::kNone ||
+               var->storage_class() == ast::StorageClass::kOutput) {
+      if (!EmitZeroValue(var->type())) {
+        return false;
+      }
     }
   }
   out_ << ";" << std::endl;
diff --git a/src/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
index 8e14e4d..cda99ae 100644
--- a/src/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -18,8 +18,15 @@
 #include "gtest/gtest.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/module.h"
+#include "src/ast/struct.h"
+#include "src/ast/struct_decoration.h"
+#include "src/ast/struct_member.h"
+#include "src/ast/struct_member_decoration.h"
+#include "src/ast/struct_member_offset_decoration.h"
 #include "src/ast/type/array_type.h"
 #include "src/ast/type/f32_type.h"
+#include "src/ast/type/matrix_type.h"
+#include "src/ast/type/struct_type.h"
 #include "src/ast/type/vector_type.h"
 #include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
@@ -44,7 +51,7 @@
   g.increment_indent();
 
   ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
-  EXPECT_EQ(g.result(), "  float a;\n");
+  EXPECT_EQ(g.result(), "  float a = 0.0f;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
@@ -60,7 +67,7 @@
   g.increment_indent();
 
   ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
-  EXPECT_EQ(g.result(), "  const float a;\n");
+  EXPECT_EQ(g.result(), "  const float a = 0.0f;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
@@ -77,13 +84,27 @@
   g.increment_indent();
 
   ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
-  EXPECT_EQ(g.result(), "  float a[5];\n");
+  EXPECT_EQ(g.result(), "  float a[5] = {0.0f};\n");
 }
 
-TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Function) {
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
   ast::type::F32Type f32;
-  auto var =
-      std::make_unique<ast::Variable>("a", ast::StorageClass::kFunction, &f32);
+
+  ast::StructMemberList members;
+  members.push_back(std::make_unique<ast::StructMember>(
+      "a", &f32, ast::StructMemberDecorationList{}));
+
+  ast::StructMemberDecorationList b_deco;
+  b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+  members.push_back(
+      std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
+
+  auto str = std::make_unique<ast::Struct>();
+  str->set_members(std::move(members));
+
+  ast::type::StructType s(std::move(str));
+
+  auto var = std::make_unique<ast::Variable>("a", ast::StorageClass::kNone, &s);
 
   ast::VariableDeclStatement stmt(std::move(var));
 
@@ -92,7 +113,44 @@
   g.increment_indent();
 
   ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
-  EXPECT_EQ(g.result(), "  float a;\n");
+  EXPECT_EQ(g.result(), R"(  struct {
+    float a;
+    float b;
+  } a = {};
+)");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec(&f32, 2);
+
+  auto var =
+      std::make_unique<ast::Variable>("a", ast::StorageClass::kFunction, &vec);
+
+  ast::VariableDeclStatement stmt(std::move(var));
+
+  ast::Module m;
+  GeneratorImpl g(&m);
+  g.increment_indent();
+
+  ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
+  EXPECT_EQ(g.result(), "  float2 a = 0.0f;\n");
+}
+
+TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix) {
+  ast::type::F32Type f32;
+  ast::type::MatrixType mat(&f32, 2, 3);
+  auto var =
+      std::make_unique<ast::Variable>("a", ast::StorageClass::kFunction, &mat);
+
+  ast::VariableDeclStatement stmt(std::move(var));
+
+  ast::Module m;
+  GeneratorImpl g(&m);
+  g.increment_indent();
+
+  ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
+  EXPECT_EQ(g.result(), "  float3x2 a = 0.0f;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
@@ -107,7 +165,7 @@
   g.increment_indent();
 
   ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
-  EXPECT_EQ(g.result(), "  float a;\n");
+  EXPECT_EQ(g.result(), "  float a = 0.0f;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_Private) {