Validate OpenCL memory and addressing model environment rules (#2589)

Signed-off-by: Kevin Petit <kevin.petit@arm.com>
diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp
index 1a684f5..b74b535 100644
--- a/source/val/validate_instruction.cpp
+++ b/source/val/validate_instruction.cpp
@@ -511,6 +511,19 @@
                << "Memory model must be VulkanKHR for WebGPU environment.";
       }
     }
+
+    if (spvIsOpenCLEnv(_.context()->target_env)) {
+      if ((_.addressing_model() != SpvAddressingModelPhysical32) &&
+          (_.addressing_model() != SpvAddressingModelPhysical64)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Addressing model must be Physical32 or Physical64 "
+               << "in the OpenCL environment.";
+      }
+      if (_.memory_model() != SpvMemoryModelOpenCL) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Memory model must be OpenCL in the OpenCL environment.";
+      }
+    }
   } else if (opcode == SpvOpExecutionMode) {
     const uint32_t entry_point = inst->word(1);
     _.RegisterExecutionModeForEntryPoint(entry_point,
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index 9f538c2..8f4bc33 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -63,6 +63,7 @@
        val_memory_test.cpp
        val_modes_test.cpp
        val_non_uniform_test.cpp
+       val_opencl_test.cpp
        val_primitives_test.cpp
        ${VAL_TEST_COMMON_SRCS}
   LIBS ${SPIRV_TOOLS}
diff --git a/test/val/val_opencl_test.cpp b/test/val/val_opencl_test.cpp
new file mode 100644
index 0000000..52e4db6
--- /dev/null
+++ b/test/val/val_opencl_test.cpp
@@ -0,0 +1,61 @@
+// Copyright (c) 2019 The Khronos Group 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.
+
+// Validation tests for OpenCL env specific checks
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "test/val/val_fixtures.h"
+
+namespace spvtools {
+namespace val {
+namespace {
+
+using testing::HasSubstr;
+
+using ValidateOpenCL = spvtest::ValidateBase<bool>;
+
+TEST_F(ValidateOpenCL, NonPhysicalAddressingModelBad) {
+  std::string spirv = R"(
+     OpCapability Kernel
+     OpMemoryModel Logical OpenCL
+)";
+
+  CompileSuccessfully(spirv);
+
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Addressing model must be Physical32 or Physical64 "
+                        "in the OpenCL environment.\n  OpMemoryModel Logical "
+                        "OpenCL\n"));
+}
+
+TEST_F(ValidateOpenCL, NonOpenCLMemoryModelBad) {
+  std::string spirv = R"(
+     OpCapability Kernel
+     OpMemoryModel Physical32 GLSL450
+)";
+
+  CompileSuccessfully(spirv);
+
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Memory model must be OpenCL in the OpenCL environment."
+                        "\n  OpMemoryModel Physical32 GLSL450\n"));
+}
+
+}  // namespace
+}  // namespace val
+}  // namespace spvtools
diff --git a/test/val/val_version_test.cpp b/test/val/val_version_test.cpp
index 70eb9b1..2b9542a 100644
--- a/test/val/val_version_test.cpp
+++ b/test/val/val_version_test.cpp
@@ -56,9 +56,10 @@
 )";
 
 const std::string opencl_spirv = R"(
+OpCapability Addresses
 OpCapability Kernel
 OpCapability Linkage
-OpMemoryModel Logical OpenCL
+OpMemoryModel Physical32 OpenCL
 )";
 
 std::string version(spv_target_env env) {