[metal-writer] Emit binary operations.

This CL adds emission of binary operations to the Metal backend.

Bug: tint:8
Change-Id: I797daadd238b718b081842b63ccefab3294bc20c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23706
Reviewed-by: David Neto <dneto@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 381c9f8..677a1cc 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -845,6 +845,7 @@
     "src/writer/wgsl/generator_impl_array_accessor_test.cc",
     "src/writer/wgsl/generator_impl_as_test.cc",
     "src/writer/wgsl/generator_impl_assign_test.cc",
+    "src/writer/wgsl/generator_impl_binary_test.cc",
     "src/writer/wgsl/generator_impl_break_test.cc",
     "src/writer/wgsl/generator_impl_call_test.cc",
     "src/writer/wgsl/generator_impl_case_test.cc",
@@ -861,7 +862,6 @@
     "src/writer/wgsl/generator_impl_kill_test.cc",
     "src/writer/wgsl/generator_impl_loop_test.cc",
     "src/writer/wgsl/generator_impl_member_accessor_test.cc",
-    "src/writer/wgsl/generator_impl_relational_test.cc",
     "src/writer/wgsl/generator_impl_return_test.cc",
     "src/writer/wgsl/generator_impl_switch_test.cc",
     "src/writer/wgsl/generator_impl_test.cc",
@@ -886,6 +886,7 @@
 source_set("tint_unittests_msl_writer_src") {
   sources = [
     "src/writer/msl/generator_impl_assign_test.cc",
+    "src/writer/msl/generator_impl_binary_test.cc",
     "src/writer/msl/generator_impl_function_test.cc",
     "src/writer/msl/generator_impl_identifier_test.cc",
     "src/writer/msl/generator_impl_return_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 82a51a4..6659416 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -465,6 +465,7 @@
     writer/wgsl/generator_impl_array_accessor_test.cc
     writer/wgsl/generator_impl_as_test.cc
     writer/wgsl/generator_impl_assign_test.cc
+    writer/wgsl/generator_impl_binary_test.cc
     writer/wgsl/generator_impl_break_test.cc
     writer/wgsl/generator_impl_call_test.cc
     writer/wgsl/generator_impl_case_test.cc
@@ -481,7 +482,6 @@
     writer/wgsl/generator_impl_kill_test.cc
     writer/wgsl/generator_impl_loop_test.cc
     writer/wgsl/generator_impl_member_accessor_test.cc
-    writer/wgsl/generator_impl_relational_test.cc
     writer/wgsl/generator_impl_return_test.cc
     writer/wgsl/generator_impl_switch_test.cc
     writer/wgsl/generator_impl_type_test.cc
@@ -494,6 +494,7 @@
 if(${TINT_BUILD_MSL_WRITER})
   list(APPEND TINT_TEST_SRCS
     writer/msl/generator_impl_assign_test.cc
+    writer/msl/generator_impl_binary_test.cc
     writer/msl/generator_impl_function_test.cc
     writer/msl/generator_impl_identifier_test.cc
     writer/msl/generator_impl_return_test.cc
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index ac1bc74..b399d45 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -15,6 +15,7 @@
 #include "src/writer/msl/generator_impl.h"
 
 #include "src/ast/assignment_statement.h"
+#include "src/ast/binary_expression.h"
 #include "src/ast/function.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/return_statement.h"
@@ -66,7 +67,91 @@
   return true;
 }
 
+bool GeneratorImpl::EmitBinary(ast::BinaryExpression* expr) {
+  out_ << "(";
+
+  if (!EmitExpression(expr->lhs())) {
+    return false;
+  }
+  out_ << " ";
+
+  switch (expr->op()) {
+    case ast::BinaryOp::kAnd:
+      out_ << "&";
+      break;
+    case ast::BinaryOp::kOr:
+      out_ << "|";
+      break;
+    case ast::BinaryOp::kXor:
+      out_ << "^";
+      break;
+    case ast::BinaryOp::kLogicalAnd:
+      out_ << "&&";
+      break;
+    case ast::BinaryOp::kLogicalOr:
+      out_ << "||";
+      break;
+    case ast::BinaryOp::kEqual:
+      out_ << "==";
+      break;
+    case ast::BinaryOp::kNotEqual:
+      out_ << "!=";
+      break;
+    case ast::BinaryOp::kLessThan:
+      out_ << "<";
+      break;
+    case ast::BinaryOp::kGreaterThan:
+      out_ << ">";
+      break;
+    case ast::BinaryOp::kLessThanEqual:
+      out_ << "<=";
+      break;
+    case ast::BinaryOp::kGreaterThanEqual:
+      out_ << ">=";
+      break;
+    case ast::BinaryOp::kShiftLeft:
+      out_ << "<<";
+      break;
+    case ast::BinaryOp::kShiftRight:
+      // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
+      // implementation-defined behaviour for negative LHS.  We may have to
+      // generate extra code to implement WGSL-specified behaviour for negative
+      // LHS.
+      out_ << ">>";
+      break;
+    case ast::BinaryOp::kAdd:
+      out_ << "+";
+      break;
+    case ast::BinaryOp::kSubtract:
+      out_ << "-";
+      break;
+    case ast::BinaryOp::kMultiply:
+      out_ << "*";
+      break;
+    case ast::BinaryOp::kDivide:
+      out_ << "/";
+      break;
+    case ast::BinaryOp::kModulo:
+      out_ << "%";
+      break;
+    case ast::BinaryOp::kNone:
+      error_ = "missing binary operation type";
+      return false;
+  }
+  out_ << " ";
+
+  if (!EmitExpression(expr->rhs())) {
+    return false;
+  }
+
+  out_ << ")";
+  return true;
+}
+
 bool GeneratorImpl::EmitExpression(ast::Expression* expr) {
+  if (expr->IsBinary()) {
+    return EmitBinary(expr->AsBinary());
+  }
   if (expr->IsIdentifier()) {
     return EmitIdentifier(expr->AsIdentifier());
   }
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index 8617c90..5ef4407 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -41,6 +41,10 @@
   /// @param stmt the statement to emit
   /// @returns true if the statement was emitted successfully
   bool EmitAssign(ast::AssignmentStatement* stmt);
+  /// Handles generating a binary expression
+  /// @param expr the binary expression
+  /// @returns true if the expression was emitted, false otherwise
+  bool EmitBinary(ast::BinaryExpression* expr);
   /// Handles generate an Expression
   /// @param expr the expression
   /// @returns true if the expression was emitted
diff --git a/src/writer/wgsl/generator_impl_relational_test.cc b/src/writer/msl/generator_impl_binary_test.cc
similarity index 91%
copy from src/writer/wgsl/generator_impl_relational_test.cc
copy to src/writer/msl/generator_impl_binary_test.cc
index 465c149..017e6ac 100644
--- a/src/writer/wgsl/generator_impl_relational_test.cc
+++ b/src/writer/msl/generator_impl_binary_test.cc
@@ -17,11 +17,11 @@
 #include "gtest/gtest.h"
 #include "src/ast/binary_expression.h"
 #include "src/ast/identifier_expression.h"
-#include "src/writer/wgsl/generator_impl.h"
+#include "src/writer/msl/generator_impl.h"
 
 namespace tint {
 namespace writer {
-namespace wgsl {
+namespace msl {
 namespace {
 
 struct BinaryData {
@@ -32,8 +32,8 @@
   out << data.op;
   return out;
 }
-using BinaryTest = testing::TestWithParam<BinaryData>;
-TEST_P(BinaryTest, Emit) {
+using MslBinaryTest = testing::TestWithParam<BinaryData>;
+TEST_P(MslBinaryTest, Emit) {
   auto params = GetParam();
 
   auto left = std::make_unique<ast::IdentifierExpression>("left");
@@ -46,8 +46,8 @@
   EXPECT_EQ(g.result(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
-    WgslGeneratorImplTest,
-    BinaryTest,
+    MslGeneratorImplTest,
+    MslBinaryTest,
     testing::Values(
         BinaryData{"(left & right)", ast::BinaryOp::kAnd},
         BinaryData{"(left | right)", ast::BinaryOp::kOr},
@@ -69,6 +69,6 @@
         BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
 
 }  // namespace
-}  // namespace wgsl
+}  // namespace msl
 }  // namespace writer
 }  // namespace tint
diff --git a/src/writer/wgsl/generator_impl_relational_test.cc b/src/writer/wgsl/generator_impl_binary_test.cc
similarity index 95%
rename from src/writer/wgsl/generator_impl_relational_test.cc
rename to src/writer/wgsl/generator_impl_binary_test.cc
index 465c149..2858f77 100644
--- a/src/writer/wgsl/generator_impl_relational_test.cc
+++ b/src/writer/wgsl/generator_impl_binary_test.cc
@@ -32,8 +32,8 @@
   out << data.op;
   return out;
 }
-using BinaryTest = testing::TestWithParam<BinaryData>;
-TEST_P(BinaryTest, Emit) {
+using WgslBinaryTest = testing::TestWithParam<BinaryData>;
+TEST_P(WgslBinaryTest, Emit) {
   auto params = GetParam();
 
   auto left = std::make_unique<ast::IdentifierExpression>("left");
@@ -47,7 +47,7 @@
 }
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
-    BinaryTest,
+    WgslBinaryTest,
     testing::Values(
         BinaryData{"(left & right)", ast::BinaryOp::kAnd},
         BinaryData{"(left | right)", ast::BinaryOp::kOr},