Add SPV_EXT_shader_image_int64 (#3852)

* Add SPV_EXT_shader_image_atomic_int64
* Added 64-bit image tests


Co-authored-by: Arkadiusz Sarwa <arkadiusz.sarwa@amd.com>
diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp
index df7973f..3f1f561 100644
--- a/source/val/validate_atomics.cpp
+++ b/source/val/validate_atomics.cpp
@@ -1,4 +1,6 @@
 // Copyright (c) 2017 Google Inc.
+// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
+// reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -151,7 +153,9 @@
         }
 
         if (spvIsVulkanEnv(_.context()->target_env) &&
-            _.GetBitWidth(result_type) != 32) {
+            (_.GetBitWidth(result_type) != 32 &&
+             (_.GetBitWidth(result_type) != 64 ||
+              !_.HasCapability(SpvCapabilityInt64ImageEXT)))) {
           switch (opcode) {
             case SpvOpAtomicSMin:
             case SpvOpAtomicUMin:
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp
index 8a2bdf1..299a3ef 100644
--- a/source/val/validate_image.cpp
+++ b/source/val/validate_image.cpp
@@ -1,4 +1,6 @@
 // Copyright (c) 2017 Google Inc.
+// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
+// reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -737,7 +739,9 @@
   if (spvIsVulkanEnv(_.context()->target_env)) {
     if ((!_.IsFloatScalarType(info.sampled_type) &&
          !_.IsIntScalarType(info.sampled_type)) ||
-        32 != _.GetBitWidth(info.sampled_type)) {
+        (32 != _.GetBitWidth(info.sampled_type) &&
+         (64 != _.GetBitWidth(info.sampled_type) ||
+          !_.HasCapability(SpvCapabilityInt64ImageEXT)))) {
       return _.diag(SPV_ERROR_INVALID_DATA, inst)
              << "Expected Sampled Type to be a 32-bit int or float "
                 "scalar type for Vulkan environment";
diff --git a/test/enum_string_mapping_test.cpp b/test/enum_string_mapping_test.cpp
index 184ae4f..9bbd8ca 100644
--- a/test/enum_string_mapping_test.cpp
+++ b/test/enum_string_mapping_test.cpp
@@ -1,4 +1,6 @@
 // Copyright (c) 2017 Google Inc.
+// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
+// reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -180,6 +182,7 @@
          {SpvCapabilityAtomicFloat32AddEXT, "AtomicFloat32AddEXT"},
          {SpvCapabilityAtomicFloat64AddEXT, "AtomicFloat64AddEXT"},
          {SpvCapabilityMultiView, "MultiView"},
+         {SpvCapabilityInt64ImageEXT, "Int64ImageEXT"},
          {SpvCapabilitySampleMaskOverrideCoverageNV,
           "SampleMaskOverrideCoverageNV"},
          {SpvCapabilityGeometryShaderPassthroughNV,
diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp
index 1a6e79c..2e84a29 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -1,4 +1,6 @@
 // Copyright (c) 2017 Google Inc.
+// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
+// reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -37,7 +39,8 @@
     const std::string& execution_model = "Fragment",
     const std::string& execution_mode = "",
     const spv_target_env env = SPV_ENV_UNIVERSAL_1_0,
-    const std::string& memory_model = "GLSL450") {
+    const std::string& memory_model = "GLSL450",
+    const std::string& declarations = "") {
   std::ostringstream ss;
   ss << R"(
 OpCapability Shader
@@ -163,6 +166,7 @@
 %u32_4 = OpConstant %u32 4
 
 %u64_0 = OpConstant %u64 0
+%u64_1 = OpConstant %u64 1
 
 %u32vec2arr4 = OpTypeArray %u32vec2 %u32_4
 %u32vec2arr3 = OpTypeArray %u32vec2 %u32_3
@@ -316,6 +320,8 @@
 )";
   }
 
+  ss << declarations;
+
   ss << R"(
 %main = OpFunction %void None %func
 %main_entry = OpLabel
@@ -737,7 +743,7 @@
 
   CompileSuccessfully(GenerateShaderCode(body).c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
-  EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 140[%140] cannot be a "
+  EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 141[%141] cannot be a "
                                                "type"));
 }
 
@@ -5071,6 +5077,102 @@
 // No negative tests for ZeroExtend since we don't truly know the
 // texel format.
 
+// Tests for 64-bit images
+static const std::string capabilities_and_extensions_image64 = R"(
+OpCapability Int64ImageEXT
+OpExtension "SPV_EXT_shader_image_int64"
+)";
+static const std::string declarations_image64 = R"(
+%type_image_u64_buffer_0002_r64ui = OpTypeImage %u64 Buffer 0 0 0 2 R64ui
+%ptr_Image_u64 = OpTypePointer Image %u64
+%ptr_image_u64_buffer_0002_r64ui = OpTypePointer Private %type_image_u64_buffer_0002_r64ui
+%private_image_u64_buffer_0002_r64ui = OpVariable %ptr_image_u64_buffer_0002_r64ui Private
+)";
+
+TEST_F(ValidateImage, Image64MissingCapability) {
+  CompileSuccessfully(GenerateShaderCode("", "", "Fragment", "",
+                                         SPV_ENV_UNIVERSAL_1_3, "GLSL450",
+                                         declarations_image64)
+                          .c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
+}
+
+TEST_F(ValidateImage, Image64MissingExtension) {
+  const std::string extra = R"(
+OpCapability Int64ImageEXT
+)";
+
+  CompileSuccessfully(GenerateShaderCode("", extra, "Fragment", "",
+                                         SPV_ENV_UNIVERSAL_1_3, "GLSL450",
+                                         declarations_image64)
+                          .c_str());
+  ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
+}
+
+TEST_F(ValidateImage, ImageTexelPointer64Success) {
+  const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_u64 %private_image_u64_buffer_0002_r64ui %u32_0 %u32_0
+%sum = OpAtomicIAdd %u64 %texel_ptr %u32_1 %u32_0 %u64_1
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body,
+                                         capabilities_and_extensions_image64,
+                                         "Fragment", "", SPV_ENV_UNIVERSAL_1_3,
+                                         "GLSL450", declarations_image64)
+                          .c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateImage, ImageTexelPointer64ResultTypeNotPointer) {
+  const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %type_image_u64_buffer_0002_r64ui %private_image_u64_buffer_0002_r64ui %u32_0 %u32_0
+%sum = OpAtomicIAdd %u64 %texel_ptr %u32_1 %u32_0 %u64_1
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body,
+                                         capabilities_and_extensions_image64,
+                                         "Fragment", "", SPV_ENV_UNIVERSAL_1_3,
+                                         "GLSL450", declarations_image64)
+                          .c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected Result Type to be OpTypePointer"));
+}
+
+TEST_F(ValidateImage, ImageTexelPointer64ResultTypeNotImageClass) {
+  const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_image_f32_cube_0101 %private_image_u64_buffer_0002_r64ui %u32_0 %u32_0
+%sum = OpAtomicIAdd %u64 %texel_ptr %u32_1 %u32_0 %u64_1
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body,
+                                         capabilities_and_extensions_image64,
+                                         "Fragment", "", SPV_ENV_UNIVERSAL_1_3,
+                                         "GLSL450", declarations_image64)
+                          .c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected Result Type to be OpTypePointer whose "
+                        "Storage Class operand is Image"));
+}
+
+TEST_F(ValidateImage, ImageTexelPointer64SampleNotZeroForImageWithMSZero) {
+  const std::string body = R"(
+%texel_ptr = OpImageTexelPointer %ptr_Image_u64 %private_image_u64_buffer_0002_r64ui %u32_0 %u32_1
+%sum = OpAtomicIAdd %u64 %texel_ptr %u32_1 %u32_0 %u64_1
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body,
+                                         capabilities_and_extensions_image64,
+                                         "Fragment", "", SPV_ENV_UNIVERSAL_1_3,
+                                         "GLSL450", declarations_image64)
+                          .c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected Sample for Image with MS 0 to be a valid "
+                        "<id> for the value 0"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools