[spirv-writer] Add a LocalSize execution mode.

In SPIR-V a compute entry point requires a WorkGroup Size constant or a
LocalSize execution mode. This CL adds a 1,1,1 execution mode as a
starting point.

Bug: tint:74
Change-Id: Ie5bf639472033dca9ffe333548e7f31d4d318768
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/21020
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 9c1094d..fc205f0 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -302,6 +302,11 @@
     push_preamble(
         spv::Op::OpExecutionMode,
         {Operand::Int(id), Operand::Int(SpvExecutionModeOriginUpperLeft)});
+  } else if (ep->stage() == ast::PipelineStage::kCompute) {
+    // TODO(dsinclair): Support LocalSize other then (1, 1, 1)
+    push_preamble(spv::Op::OpExecutionMode,
+                  {Operand::Int(id), Operand::Int(SpvExecutionModeLocalSize),
+                   Operand::Int(1), Operand::Int(1), Operand::Int(1)});
   }
 
   return true;
diff --git a/src/writer/spirv/builder_entry_point_test.cc b/src/writer/spirv/builder_entry_point_test.cc
index ae55071..2f1d8e0 100644
--- a/src/writer/spirv/builder_entry_point_test.cc
+++ b/src/writer/spirv/builder_entry_point_test.cc
@@ -39,9 +39,7 @@
   b.set_func_name_to_id("frag_main", 2);
   ASSERT_TRUE(b.GenerateEntryPoint(&ep));
 
-  auto preamble = b.preamble();
-  ASSERT_EQ(preamble.size(), 1u);
-  EXPECT_EQ(DumpInstruction(preamble[0]), R"(OpEntryPoint Fragment %2 "main"
+  EXPECT_EQ(DumpInstructions(b.preamble()), R"(OpEntryPoint Fragment %2 "main"
 )");
 }
 
@@ -53,9 +51,7 @@
   b.set_func_name_to_id("compute_main", 3);
   ASSERT_TRUE(b.GenerateEntryPoint(&ep));
 
-  auto preamble = b.preamble();
-  ASSERT_EQ(preamble.size(), 1u);
-  EXPECT_EQ(DumpInstruction(preamble[0]),
+  EXPECT_EQ(DumpInstructions(b.preamble()),
             R"(OpEntryPoint GLCompute %3 "compute_main"
 )");
 }
@@ -153,9 +149,21 @@
   b.set_func_name_to_id("frag_main", 2);
   ASSERT_TRUE(b.GenerateExecutionModes(&ep));
 
-  auto preamble = b.preamble();
-  ASSERT_EQ(preamble.size(), 1u);
-  EXPECT_EQ(DumpInstruction(preamble[0]), R"(OpExecutionMode %2 OriginUpperLeft
+  EXPECT_EQ(DumpInstructions(b.preamble()),
+            R"(OpExecutionMode %2 OriginUpperLeft
+)");
+}
+
+TEST_F(BuilderTest, ExecutionModel_Compute_LocalSize) {
+  ast::EntryPoint ep(ast::PipelineStage::kCompute, "main", "main");
+
+  ast::Module mod;
+  Builder b(&mod);
+  b.set_func_name_to_id("main", 2);
+  ASSERT_TRUE(b.GenerateExecutionModes(&ep));
+
+  EXPECT_EQ(DumpInstructions(b.preamble()),
+            R"(OpExecutionMode %2 LocalSize 1 1 1
 )");
 }