writer/hlsl: Implement generation of module-scope vars

Implement emission of module scope variables of the private and workgroup storage classes.
Fix tests that were incorrectly emitting these as function-scope variables.

Change-Id: I509a7388794f4a57b06a3859d10afa2611d84991
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48222
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index b7dd0d2..fed3572 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -1885,16 +1885,33 @@
         continue;  // Global already emitted
       }
 
-      if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
-        out << "groupshared ";
-      } else if (!unwrapped_type->IsAnyOf<type::Texture, type::Sampler>()) {
-        continue;  // Not interested in this type
+      make_indent(out);
+
+      std::ostringstream constructor_out;
+      if (auto* constructor = decl->constructor()) {
+        if (!EmitExpression(out, constructor_out, constructor)) {
+          return false;
+        }
       }
 
-      if (!EmitType(out, var->DeclaredType(), var->StorageClass(), "")) {
+      switch (var->StorageClass()) {
+        case ast::StorageClass::kPrivate:
+        case ast::StorageClass::kUniformConstant:
+          break;
+        case ast::StorageClass::kWorkgroup:
+          out << "groupshared ";
+          break;
+        default:
+          continue;  // Not interested in this storage class
+      }
+
+      auto name = builder_.Symbols().NameFor(decl->symbol());
+      if (!EmitType(out, var->DeclaredType(), var->StorageClass(), name)) {
         return false;
       }
-      out << " " << builder_.Symbols().NameFor(decl->symbol());
+      if (!var->DeclaredType()->UnwrapAliasIfNeeded()->Is<type::Array>()) {
+        out << " " << name;
+      }
 
       const char* register_space = nullptr;
 
@@ -1917,6 +1934,10 @@
             << ", space" << bp.group->value() << ")";
       }
 
+      if (constructor_out.str().length()) {
+        out << " = " << constructor_out.str();
+      }
+
       out << ";" << std::endl;
 
       add_newline = true;
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index 315b132..04aeb5e 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -139,6 +139,8 @@
   float mem;
 };
 
+Data str;
+
 [numthreads(1, 1, 1)]
 void test_function() {
   float tint_symbol = str.mem;
diff --git a/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index 7fa67cc..e69f8df 100644
--- a/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "gmock/gmock.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/writer/hlsl/test_helper.h"
 
@@ -20,12 +21,14 @@
 namespace hlsl {
 namespace {
 
+using ::testing::HasSubstr;
+
 using HlslGeneratorImplTest_VariableDecl = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
-  auto* var = Global("a", ty.f32(), ast::StorageClass::kInput);
-
+  auto* var = Var("a", ty.f32(), ast::StorageClass::kFunction);
   auto* stmt = create<ast::VariableDeclStatement>(var);
+  WrapInFunction(stmt);
 
   GeneratorImpl& gen = Build();
 
@@ -37,7 +40,6 @@
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
   auto* var = Const("a", ty.f32());
-
   auto* stmt = create<ast::VariableDeclStatement>(var);
   WrapInFunction(stmt);
 
@@ -50,58 +52,43 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
-  auto* var = Global("a", ty.array<f32, 5>(), ast::StorageClass::kInput);
+  auto* var = Var("a", ty.array<f32, 5>(), ast::StorageClass::kFunction);
 
-  auto* stmt = create<ast::VariableDeclStatement>(var);
+  WrapInFunction(var, Expr("a"));
 
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
-  EXPECT_EQ(result(), "  float a[5];\n");
-}
-
-TEST_F(HlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Function) {
-  auto* var = Global("a", ty.f32(), ast::StorageClass::kFunction);
-
-  auto* stmt = create<ast::VariableDeclStatement>(var);
-
-  GeneratorImpl& gen = Build();
-
-  gen.increment_indent();
-
-  ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
-  EXPECT_EQ(result(), "  float a;\n");
+  ASSERT_TRUE(gen.Generate(out)) << gen.error();
+  EXPECT_THAT(result(), HasSubstr("  float a[5];\n"));
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
-  auto* var = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+  Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* stmt = create<ast::VariableDeclStatement>(var);
+  WrapInFunction(Expr("a"));
 
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
-  EXPECT_EQ(result(), "  float a;\n");
+  ASSERT_TRUE(gen.Generate(out)) << gen.error();
+  EXPECT_THAT(result(), HasSubstr("  float a;\n"));
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl,
        Emit_VariableDeclStatement_Initializer_Private) {
   Global("initializer", ty.f32(), ast::StorageClass::kInput);
-  auto* var =
-      Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+  Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
 
-  auto* stmt = create<ast::VariableDeclStatement>(var);
+  WrapInFunction(Expr("a"));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
-  EXPECT_EQ(result(), R"(float a = initializer;
-)");
+  ASSERT_TRUE(gen.Generate(out)) << gen.error();
+  EXPECT_THAT(result(), HasSubstr(R"(float a = initializer;
+)"));
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl,