[spirv-writer] Add assignment statements

This Cl adds assignment statement generation to the SPIR-V writer.

Bug: tint:5
Change-Id: I17876c0211e4b4e061d39e08fc6a433098252f38
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/18621
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6f09163..2b9bbbc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -415,6 +415,7 @@
 if(${TINT_BUILD_SPV_WRITER})
   list(APPEND TINT_TEST_SRCS
     writer/spirv/binary_writer_test.cc
+    writer/spirv/builder_assign_test.cc
     writer/spirv/builder_constructor_expression_test.cc
     writer/spirv/builder_entry_point_test.cc
     writer/spirv/builder_function_test.cc
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index be9c570..69bcdb8 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -17,13 +17,14 @@
 #include <utility>
 
 #include "spirv/unified1/spirv.h"
+#include "src/ast/assignment_statement.h"
 #include "src/ast/binding_decoration.h"
 #include "src/ast/bool_literal.h"
-#include "src/ast/identifier_expression.h"
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/constructor_expression.h"
 #include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
+#include "src/ast/identifier_expression.h"
 #include "src/ast/int_literal.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/return_statement.h"
@@ -155,6 +156,21 @@
   }
 }
 
+bool Builder::GenerateAssignStatement(ast::AssignmentStatement* assign) {
+  auto lhs_id = GenerateExpression(assign->lhs());
+  if (lhs_id == 0) {
+    return false;
+  }
+  auto rhs_id = GenerateExpression(assign->rhs());
+  if (rhs_id == 0) {
+    return false;
+  }
+
+  push_function_inst(spv::Op::OpStore,
+                     {Operand::Int(lhs_id), Operand::Int(rhs_id)});
+  return true;
+}
+
 bool Builder::GenerateEntryPoint(ast::EntryPoint* ep) {
   auto name = ep->name();
   if (name.empty()) {
@@ -374,8 +390,10 @@
   return true;
 }
 
-uint32_t Builder::GenerateIdentifierExpression(ast::IdentifierExpression* expr) {
-  for (auto iter = variable_stack_.rbegin(); iter != variable_stack_.rend(); ++iter) {
+uint32_t Builder::GenerateIdentifierExpression(
+    ast::IdentifierExpression* expr) {
+  for (auto iter = variable_stack_.rbegin(); iter != variable_stack_.rend();
+       ++iter) {
     auto& map = *iter;
 
     // TODO(dsinclair): handle names with namespaces in them ...
@@ -513,6 +531,9 @@
 }
 
 bool Builder::GenerateStatement(ast::Statement* stmt) {
+  if (stmt->IsAssign()) {
+    return GenerateAssignStatement(stmt->AsAssign());
+  }
   if (stmt->IsReturn()) {
     return GenerateReturnStatement(stmt->AsReturn());
   }
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 479da1b..8bcad6e 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -143,6 +143,10 @@
   /// @returns the SPIR-V builtin or SpvBuiltInMax on error.
   SpvBuiltIn ConvertBuiltin(ast::Builtin builtin) const;
 
+  /// Generates an assignment statement
+  /// @param assign the statement to generate
+  /// @returns true if the statement was successfully generated
+  bool GenerateAssignStatement(ast::AssignmentStatement* assign);
   /// Generates an entry point instruction
   /// @param ep the entry point
   /// @returns true if the instruction was generated, false otherwise
diff --git a/src/writer/spirv/builder_assign_test.cc b/src/writer/spirv/builder_assign_test.cc
new file mode 100644
index 0000000..5c7430e
--- /dev/null
+++ b/src/writer/spirv/builder_assign_test.cc
@@ -0,0 +1,72 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <memory>
+
+#include "gtest/gtest.h"
+#include "src/ast/assignment_statement.h"
+#include "src/ast/float_literal.h"
+#include "src/ast/identifier_expression.h"
+#include "src/ast/scalar_constructor_expression.h"
+#include "src/ast/type/f32_type.h"
+#include "src/ast/type/vector_type.h"
+#include "src/writer/spirv/builder.h"
+#include "src/writer/spirv/spv_dump.h"
+
+namespace tint {
+namespace writer {
+namespace spirv {
+namespace {
+
+using BuilderTest = testing::Test;
+
+TEST_F(BuilderTest, Assign_Var) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec(&f32, 3);
+
+  ast::Variable v("var", ast::StorageClass::kOutput, &f32);
+
+  Builder b;
+  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  ASSERT_FALSE(b.has_error()) << b.error();
+
+  auto ident = std::make_unique<ast::IdentifierExpression>("var");
+  auto val = std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f));
+
+  ast::AssignmentStatement assign(std::move(ident), std::move(val));
+
+  b.push_function(Function{});
+
+  EXPECT_TRUE(b.GenerateAssignStatement(&assign)) << b.error();
+  EXPECT_FALSE(b.has_error());
+
+  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+%2 = OpTypePointer Output %3
+%1 = OpVariable %2 Output
+%4 = OpConstant %3 1
+)");
+
+  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %1 %4
+)");
+}
+
+TEST_F(BuilderTest, DISABLED_Assign_StructMember) {}
+
+TEST_F(BuilderTest, DISABLED_Assign_Vector) {}
+
+}  // namespace
+}  // namespace spirv
+}  // namespace writer
+}  // namespace tint
diff --git a/src/writer/spirv/builder_ident_expression_test.cc b/src/writer/spirv/builder_ident_expression_test.cc
index ebf0159..0983c72 100644
--- a/src/writer/spirv/builder_ident_expression_test.cc
+++ b/src/writer/spirv/builder_ident_expression_test.cc
@@ -16,14 +16,14 @@
 
 #include "gtest/gtest.h"
 #include "src/ast/float_literal.h"
+#include "src/ast/identifier_expression.h"
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/type/f32_type.h"
-#include "src/ast/type_constructor_expression.h"
 #include "src/ast/type/vector_type.h"
+#include "src/ast/type_constructor_expression.h"
+#include "src/ast/variable.h"
 #include "src/writer/spirv/builder.h"
 #include "src/writer/spirv/spv_dump.h"
-#include "src/ast/identifier_expression.h"
-#include "src/ast/variable.h"
 
 namespace tint {
 namespace writer {
@@ -144,4 +144,3 @@
 }  // namespace spirv
 }  // namespace writer
 }  // namespace tint
-