Adding valilidation checks for OpEntryPoint duplicate names and execution mode (#2862)

diff --git a/source/val/validate.cpp b/source/val/validate.cpp
index 6f1a26c..e4123a4 100644
--- a/source/val/validate.cpp
+++ b/source/val/validate.cpp
@@ -272,6 +272,7 @@
     return error;
   }
 
+  std::vector<Instruction*> visited_entry_points;
   for (auto& instruction : vstate->ordered_instructions()) {
     {
       // In order to do this work outside of Process Instruction we need to be
@@ -293,6 +294,24 @@
 
         vstate->RegisterEntryPoint(entry_point, execution_model,
                                    std::move(desc));
+
+        if (visited_entry_points.size() > 0) {
+          for (const Instruction* check_inst : visited_entry_points) {
+            const auto check_execution_model =
+                check_inst->GetOperandAs<SpvExecutionModel>(0);
+            const char* check_str = reinterpret_cast<const char*>(
+                check_inst->words().data() + inst->operand(2).offset);
+            const std::string check_name(check_str);
+
+            if (desc.name == check_name &&
+                execution_model == check_execution_model) {
+              return vstate->diag(SPV_ERROR_INVALID_DATA, inst)
+                     << "2 Entry points cannot share the same name and "
+                        "ExecutionMode.";
+            }
+          }
+        }
+        visited_entry_points.push_back(inst);
       }
       if (inst->opcode() == SpvOpFunctionCall) {
         if (!vstate->in_function_body()) {
diff --git a/source/val/validate.h b/source/val/validate.h
index b6c4072..da3d0b8 100644
--- a/source/val/validate.h
+++ b/source/val/validate.h
@@ -208,7 +208,7 @@
 spv_result_t ValidateExecutionLimitations(ValidationState_t& _,
                                           const Instruction* inst);
 
-/// Validates restricted  uses of 8- and 16-bit types.
+/// Validates restricted uses of 8- and 16-bit types.
 ///
 /// Validates shaders that uses 8- or 16-bit storage capabilities, but not full
 /// capabilities only have appropriate uses of those types.
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index b6937b1..d4bfe1d 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -35,6 +35,7 @@
        val_data_test.cpp
        val_decoration_test.cpp
        val_derivatives_test.cpp
+       val_entry_point.cpp
        val_explicit_reserved_test.cpp
        val_extensions_test.cpp
        val_ext_inst_test.cpp
diff --git a/test/val/val_entry_point.cpp b/test/val/val_entry_point.cpp
new file mode 100644
index 0000000..f28cf5d
--- /dev/null
+++ b/test/val/val_entry_point.cpp
@@ -0,0 +1,76 @@
+// Copyright (c) 2019 Samsung Inc
+//
+// 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 <string>
+
+#include "gmock/gmock.h"
+#include "test/unit_spirv.h"
+#include "test/val/val_fixtures.h"
+
+namespace spvtools {
+namespace {
+
+using ::testing::Eq;
+using ::testing::HasSubstr;
+
+using ValidateEntryPoints = spvtest::ValidateBase<bool>;
+
+TEST_F(ValidateEntryPoints, DuplicateEntryPoints) {
+  const std::string body = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "foo"
+OpEntryPoint GLCompute %4 "foo"
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%3 = OpFunction %1 None %2
+%20 = OpLabel
+OpReturn
+OpFunctionEnd
+%4 = OpFunction %1 None %2
+%21 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Entry points cannot share the same name"));
+}
+
+TEST_F(ValidateEntryPoints, UniqueEntryPoints) {
+  const std::string body = R"(
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "foo"
+OpEntryPoint GLCompute %4 "foo2"
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%3 = OpFunction %1 None %2
+%20 = OpLabel
+OpReturn
+OpFunctionEnd
+%4 = OpFunction %1 None %2
+%21 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(body);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+}  // namespace
+}  // namespace spvtools
diff --git a/utils/check_copyright.py b/utils/check_copyright.py
index 5a95e32..cfeef80 100755
--- a/utils/check_copyright.py
+++ b/utils/check_copyright.py
@@ -30,7 +30,8 @@
            'LunarG Inc.',
            'Google Inc.',
            'Google LLC',
-           'Pierre Moreau']
+           'Pierre Moreau',
+           'Samsung Inc']
 CURRENT_YEAR='2019'
 
 YEARS = '(2014-2016|2015-2016|2016|2016-2017|2017|2018|2019)'