Add conversion of SpvExecutionModel

Bug: tint:3
Change-Id: I2b1a12beea9343ab3a8db50308e2f6fd790c654b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17581
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a64b78b..0fcbb43 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -198,6 +198,8 @@
 
 if(${TINT_BUILD_SPV_READER})
   list(APPEND TINT_LIB_SRCS
+    reader/spirv/enum_converter.h
+    reader/spirv/enum_converter.cc
     reader/spirv/fail_stream.h
     reader/spirv/namer.cc
     reader/spirv/namer.h
@@ -314,6 +316,7 @@
 
 if(${TINT_BUILD_SPV_READER})
   list(APPEND TINT_TEST_SRCS
+    reader/spirv/enum_converter_test.cc
     reader/spirv/fail_stream_test.cc
     reader/spirv/namer_test.cc
     reader/spirv/parser_impl_import_test.cc
diff --git a/src/reader/spirv/enum_converter.cc b/src/reader/spirv/enum_converter.cc
new file mode 100644
index 0000000..ebbde75
--- /dev/null
+++ b/src/reader/spirv/enum_converter.cc
@@ -0,0 +1,43 @@
+// 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 "src/reader/spirv/enum_converter.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+
+EnumConverter::EnumConverter(const FailStream& fs) : fail_stream_(fs) {}
+
+EnumConverter::~EnumConverter() = default;
+
+ast::PipelineStage EnumConverter::ToPipelineStage(SpvExecutionModel model) {
+  switch (model) {
+    case SpvExecutionModelVertex:
+      return ast::PipelineStage::kVertex;
+    case SpvExecutionModelFragment:
+      return ast::PipelineStage::kFragment;
+    case SpvExecutionModelGLCompute:
+      return ast::PipelineStage::kCompute;
+    default:
+      break;
+  }
+
+  Fail() << "unknown SPIR-V execution model: " << uint32_t(model);
+  return ast::PipelineStage::kNone;
+}
+
+}  // namespace spirv
+}  // namespace reader
+}  // namespace tint
diff --git a/src/reader/spirv/enum_converter.h b/src/reader/spirv/enum_converter.h
new file mode 100644
index 0000000..0af8312
--- /dev/null
+++ b/src/reader/spirv/enum_converter.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef SRC_READER_SPIRV_ENUM_CONVERTER_H_
+#define SRC_READER_SPIRV_ENUM_CONVERTER_H_
+
+#include "spirv/unified1/spirv.h"
+#include "src/ast/pipeline_stage.h"
+#include "src/reader/spirv/fail_stream.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+
+/// A converter from SPIR-V enums to Tint AST enums.
+class EnumConverter {
+ public:
+  /// Creates a new enum converter.
+  /// @param fail_stream the error reporting stream.
+  explicit EnumConverter(const FailStream& fail_stream);
+  /// Destructor
+  ~EnumConverter();
+
+  /// Converts a SPIR-V execution model to a Tint pipeline stage.
+  /// On failure, logs an error and returns kNone
+  /// @param model the SPIR-V entry point execution model
+  /// @returns a Tint AST pipeline stage
+  ast::PipelineStage ToPipelineStage(SpvExecutionModel model);
+
+ private:
+  /// Registers a failure and returns a stream for logg diagnostics.
+  /// @returns a failure stream
+  FailStream Fail() { return fail_stream_.Fail(); }
+
+  FailStream fail_stream_;
+};
+
+}  // namespace spirv
+}  // namespace reader
+}  // namespace tint
+
+#endif  // SRC_READER_SPIRV_ENUM_CONVERTER_H_
diff --git a/src/reader/spirv/enum_converter_test.cc b/src/reader/spirv/enum_converter_test.cc
new file mode 100644
index 0000000..b4450d6
--- /dev/null
+++ b/src/reader/spirv/enum_converter_test.cc
@@ -0,0 +1,93 @@
+// 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 "src/reader/spirv/enum_converter.h"
+
+#include <ostream>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "spirv/unified1/spirv.h"
+#include "src/ast/pipeline_stage.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+namespace {
+
+struct PipelineStageCase {
+  SpvExecutionModel model;
+  bool expect_success;
+  ast::PipelineStage expected;
+};
+inline std::ostream& operator<<(std::ostream& out, PipelineStageCase psc) {
+  out << "PipelineStageCase{ SpvExecutionModel:" << int(psc.model)
+      << " expect_success?:" << int(psc.expect_success)
+      << " expected:" << int(psc.expected) << "}";
+  return out;
+}
+
+class SpvPipelineStageTest : public testing::TestWithParam<PipelineStageCase> {
+ public:
+  SpvPipelineStageTest()
+      : success_(true),
+        fail_stream_(&success_, &errors_),
+        converter_(fail_stream_) {}
+
+  std::string error() const { return errors_.str(); }
+
+ protected:
+  bool success_ = true;
+  std::stringstream errors_;
+  FailStream fail_stream_;
+  EnumConverter converter_;
+};
+
+TEST_P(SpvPipelineStageTest, Samples) {
+  const auto params = GetParam();
+
+  const auto result = converter_.ToPipelineStage(params.model);
+  EXPECT_EQ(success_, params.expect_success);
+  if (params.expect_success) {
+    EXPECT_EQ(result, params.expected);
+    EXPECT_TRUE(error().empty());
+  } else {
+    EXPECT_EQ(result, params.expected);
+    EXPECT_THAT(error(),
+                ::testing::StartsWith("unknown SPIR-V execution model:"));
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    EnumConverterGood,
+    SpvPipelineStageTest,
+    testing::Values(PipelineStageCase{SpvExecutionModelVertex, true,
+                                      ast::PipelineStage::kVertex},
+                    PipelineStageCase{SpvExecutionModelFragment, true,
+                                      ast::PipelineStage::kFragment},
+                    PipelineStageCase{SpvExecutionModelGLCompute, true,
+                                      ast::PipelineStage::kCompute}));
+
+INSTANTIATE_TEST_SUITE_P(
+    EnumConverterBad,
+    SpvPipelineStageTest,
+    testing::Values(PipelineStageCase{SpvExecutionModel(9999), false,
+                                      ast::PipelineStage::kNone},
+                    PipelineStageCase{SpvExecutionModelTessellationControl,
+                                      false, ast::PipelineStage::kNone}));
+
+}  // namespace
+}  // namespace spirv
+}  // namespace reader
+}  // namespace tint