spirv-val: Add SPV_KHR_ray_tracing storage class (#4868)

* Added VUID labels
diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp
index 425a8d3..5571aa6 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -438,11 +438,11 @@
       storage_class != SpvStorageClassCrossWorkgroup &&
       storage_class != SpvStorageClassPrivate &&
       storage_class != SpvStorageClassFunction &&
-      storage_class != SpvStorageClassRayPayloadNV &&
-      storage_class != SpvStorageClassIncomingRayPayloadNV &&
-      storage_class != SpvStorageClassHitAttributeNV &&
-      storage_class != SpvStorageClassCallableDataNV &&
-      storage_class != SpvStorageClassIncomingCallableDataNV) {
+      storage_class != SpvStorageClassRayPayloadKHR &&
+      storage_class != SpvStorageClassIncomingRayPayloadKHR &&
+      storage_class != SpvStorageClassHitAttributeKHR &&
+      storage_class != SpvStorageClassCallableDataKHR &&
+      storage_class != SpvStorageClassIncomingCallableDataKHR) {
     bool storage_input_or_output = storage_class == SpvStorageClassInput ||
                                    storage_class == SpvStorageClassOutput;
     bool builtin = false;
@@ -889,8 +889,11 @@
            << "' is not a pointer type.";
   }
 
-  const auto pointee_type = _.FindDef(pointer_type->GetOperandAs<uint32_t>(2));
-  if (!pointee_type || result_type->id() != pointee_type->id()) {
+  uint32_t pointee_data_type;
+  uint32_t storage_class;
+  if (!_.GetPointerTypeInfo(pointer_type->id(), &pointee_data_type,
+                            &storage_class) ||
+      result_type->id() != pointee_data_type) {
     return _.diag(SPV_ERROR_INVALID_ID, inst)
            << "OpLoad Result Type <id> '" << _.getIdName(inst->type_id())
            << "' does not match Pointer <id> '" << _.getIdName(pointer->id())
@@ -964,6 +967,26 @@
       return _.diag(SPV_ERROR_INVALID_ID, inst)
              << "OpStore Pointer <id> '" << _.getIdName(pointer_id)
              << "' storage class is read-only";
+    } else if (storage_class == SpvStorageClassShaderRecordBufferKHR) {
+      return _.diag(SPV_ERROR_INVALID_ID, inst)
+             << "ShaderRecordBufferKHR Storage Class variables are read only";
+    } else if (storage_class == SpvStorageClassHitAttributeKHR) {
+      std::string errorVUID = _.VkErrorID(4703);
+      _.function(inst->function()->id())
+          ->RegisterExecutionModelLimitation(
+              [errorVUID](SpvExecutionModel model, std::string* message) {
+                if (model == SpvExecutionModelAnyHitKHR ||
+                    model == SpvExecutionModelClosestHitKHR) {
+                  if (message) {
+                    *message =
+                        errorVUID +
+                        "HitAttributeKHR Storage Class variables are read only "
+                        "with AnyHitKHR and ClosestHitKHR";
+                  }
+                  return false;
+                }
+                return true;
+              });
     }
 
     if (spvIsVulkanEnv(_.context()->target_env) &&
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 2702b2b..3501e8c 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -608,7 +608,8 @@
       std::string errorVUID = VkErrorID(4644);
       function(consumer->function()->id())
           ->RegisterExecutionModelLimitation([errorVUID](
-              SpvExecutionModel model, std::string* message) {
+                                                 SpvExecutionModel model,
+                                                 std::string* message) {
             if (model == SpvExecutionModelGLCompute ||
                 model == SpvExecutionModelRayGenerationKHR ||
                 model == SpvExecutionModelIntersectionKHR ||
@@ -634,7 +635,8 @@
       std::string errorVUID = VkErrorID(4645);
       function(consumer->function()->id())
           ->RegisterExecutionModelLimitation([errorVUID](
-              SpvExecutionModel model, std::string* message) {
+                                                 SpvExecutionModel model,
+                                                 std::string* message) {
             if (model != SpvExecutionModelGLCompute &&
                 model != SpvExecutionModelTaskNV &&
                 model != SpvExecutionModelMeshNV) {
@@ -650,6 +652,116 @@
           });
     }
   }
+
+  if (storage_class == SpvStorageClassCallableDataKHR) {
+    std::string errorVUID = VkErrorID(4704);
+    function(consumer->function()->id())
+        ->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
+                                                       std::string* message) {
+          if (model != SpvExecutionModelRayGenerationKHR &&
+              model != SpvExecutionModelClosestHitKHR &&
+              model != SpvExecutionModelCallableKHR &&
+              model != SpvExecutionModelMissKHR) {
+            if (message) {
+              *message = errorVUID +
+                         "CallableDataKHR Storage Class is limited to "
+                         "RayGenerationKHR, ClosestHitKHR, CallableKHR, and "
+                         "MissKHR execution model";
+            }
+            return false;
+          }
+          return true;
+        });
+  } else if (storage_class == SpvStorageClassIncomingCallableDataKHR) {
+    std::string errorVUID = VkErrorID(4705);
+    function(consumer->function()->id())
+        ->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
+                                                       std::string* message) {
+          if (model != SpvExecutionModelCallableKHR) {
+            if (message) {
+              *message = errorVUID +
+                         "IncomingCallableDataKHR Storage Class is limited to "
+                         "CallableKHR execution model";
+            }
+            return false;
+          }
+          return true;
+        });
+  } else if (storage_class == SpvStorageClassRayPayloadKHR) {
+    std::string errorVUID = VkErrorID(4698);
+    function(consumer->function()->id())
+        ->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
+                                                       std::string* message) {
+          if (model != SpvExecutionModelRayGenerationKHR &&
+              model != SpvExecutionModelClosestHitKHR &&
+              model != SpvExecutionModelMissKHR) {
+            if (message) {
+              *message =
+                  errorVUID +
+                  "RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
+                  "ClosestHitKHR, and MissKHR execution model";
+            }
+            return false;
+          }
+          return true;
+        });
+  } else if (storage_class == SpvStorageClassHitAttributeKHR) {
+    std::string errorVUID = VkErrorID(4701);
+    function(consumer->function()->id())
+        ->RegisterExecutionModelLimitation(
+            [errorVUID](SpvExecutionModel model, std::string* message) {
+              if (model != SpvExecutionModelIntersectionKHR &&
+                  model != SpvExecutionModelAnyHitKHR &&
+                  model != SpvExecutionModelClosestHitKHR) {
+                if (message) {
+                  *message = errorVUID +
+                             "HitAttributeKHR Storage Class is limited to "
+                             "IntersectionKHR, AnyHitKHR, sand ClosestHitKHR "
+                             "execution model";
+                }
+                return false;
+              }
+              return true;
+            });
+  } else if (storage_class == SpvStorageClassIncomingRayPayloadKHR) {
+    std::string errorVUID = VkErrorID(4699);
+    function(consumer->function()->id())
+        ->RegisterExecutionModelLimitation(
+            [errorVUID](SpvExecutionModel model, std::string* message) {
+              if (model != SpvExecutionModelAnyHitKHR &&
+                  model != SpvExecutionModelClosestHitKHR &&
+                  model != SpvExecutionModelMissKHR) {
+                if (message) {
+                  *message =
+                      errorVUID +
+                      "IncomingRayPayloadKHR Storage Class is limited to "
+                      "AnyHitKHR, ClosestHitKHR, and MissKHR execution model";
+                }
+                return false;
+              }
+              return true;
+            });
+  } else if (storage_class == SpvStorageClassShaderRecordBufferKHR) {
+    function(consumer->function()->id())
+        ->RegisterExecutionModelLimitation(
+            [](SpvExecutionModel model, std::string* message) {
+              if (model != SpvExecutionModelRayGenerationKHR &&
+                  model != SpvExecutionModelIntersectionKHR &&
+                  model != SpvExecutionModelAnyHitKHR &&
+                  model != SpvExecutionModelClosestHitKHR &&
+                  model != SpvExecutionModelCallableKHR &&
+                  model != SpvExecutionModelMissKHR) {
+                if (message) {
+                  *message =
+                      "ShaderRecordBufferKHR Storage Class is limited to "
+                      "RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
+                      "ClosestHitKHR, CallableKHR, and MissKHR execution model";
+                }
+                return false;
+              }
+              return true;
+            });
+  }
 }
 
 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
@@ -1911,6 +2023,18 @@
       return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
     case 4686:
       return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
+    case 4698:
+      return VUID_WRAP(VUID-StandaloneSpirv-RayPayloadKHR-04698);
+    case 4699:
+      return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699);
+    case 4701:
+      return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04701);
+    case 4703:
+      return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04703);
+    case 4704:
+      return VUID_WRAP(VUID-StandaloneSpirv-CallableDataKHR-04704);
+    case 4705:
+      return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04705);
     case 4708:
       return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708);
     case 4710:
diff --git a/test/val/val_storage_test.cpp b/test/val/val_storage_test.cpp
index ae4047b..600e5b9 100644
--- a/test/val/val_storage_test.cpp
+++ b/test/val/val_storage_test.cpp
@@ -251,30 +251,46 @@
               HasSubstr("OpFunctionCall Argument <id> '"));
 }
 
-TEST_P(ValidateStorageExecutionModel, VulkanOutsideStoreFailure) {
-  std::stringstream ss;
+std::string GenerateExecutionModelCode(const std::string& execution_model,
+                                       const std::string& storage_class,
+                                       bool store) {
+  const std::string mode = (execution_model.compare("GLCompute") == 0)
+                               ? "OpExecutionMode %func LocalSize 1 1 1"
+                               : "";
+  const std::string operation =
+      (store) ? "OpStore %var %int0" : "%load = OpLoad %intt %var";
+  std::ostringstream ss;
   ss << R"(
               OpCapability Shader
               OpCapability RayTracingKHR
               OpExtension "SPV_KHR_ray_tracing"
               OpMemoryModel Logical GLSL450
               OpEntryPoint )"
-     << GetParam() << R"(  %func "func" %output
-              OpDecorate %output Location 0
+     << execution_model << R"( %func "func" %var
+              )" << mode << R"(
+              OpDecorate %var Location 0
 %intt       = OpTypeInt 32 0
 %int0       = OpConstant %intt 0
 %voidt      = OpTypeVoid
 %vfunct     = OpTypeFunction %voidt
-%outputptrt = OpTypePointer Output %intt
-%output     = OpVariable %outputptrt Output
+%ptr        = OpTypePointer )"
+     << storage_class << R"( %intt
+%var        = OpVariable %ptr )" << storage_class << R"(
 %func       = OpFunction %voidt None %vfunct
 %funcl      = OpLabel
-              OpStore %output %int0
+              )" << operation << R"(
               OpReturn
               OpFunctionEnd
 )";
 
-  CompileSuccessfully(ss.str(), SPV_ENV_VULKAN_1_0);
+  return ss.str();
+}
+
+TEST_P(ValidateStorageExecutionModel, VulkanOutsideStoreFailure) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "Output", true).c_str(),
+      SPV_ENV_VULKAN_1_0);
   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
   EXPECT_THAT(getDiagnosticString(),
               AnyVUID("VUID-StandaloneSpirv-None-04644"));
@@ -285,11 +301,262 @@
                 "ClosestHitKHR, MissKHR, or CallableKHR execution models"));
 }
 
+TEST_P(ValidateStorageExecutionModel, CallableDataStore) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "CallableDataKHR", true)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("RayGenerationKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("CallableKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-CallableDataKHR-04704"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr(
+            "CallableDataKHR Storage Class is limited to RayGenerationKHR, "
+            "ClosestHitKHR, CallableKHR, and MissKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, CallableDataLoad) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "CallableDataKHR", false)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("RayGenerationKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("CallableKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-CallableDataKHR-04704"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr(
+            "CallableDataKHR Storage Class is limited to RayGenerationKHR, "
+            "ClosestHitKHR, CallableKHR, and MissKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, IncomingCallableDataStore) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(GenerateExecutionModelCode(
+                          execution_model, "IncomingCallableDataKHR", true)
+                          .c_str(),
+                      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("CallableKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04705"));
+    EXPECT_THAT(getDiagnosticString(),
+                HasSubstr("IncomingCallableDataKHR Storage Class is limited to "
+                          "CallableKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, IncomingCallableDataLoad) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(GenerateExecutionModelCode(
+                          execution_model, "IncomingCallableDataKHR", false)
+                          .c_str(),
+                      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("CallableKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04705"));
+    EXPECT_THAT(getDiagnosticString(),
+                HasSubstr("IncomingCallableDataKHR Storage Class is limited to "
+                          "CallableKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, RayPayloadStore) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "RayPayloadKHR", true)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("RayGenerationKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-RayPayloadKHR-04698"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr("RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
+                  "ClosestHitKHR, and MissKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, RayPayloadLoad) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "RayPayloadKHR", false)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("RayGenerationKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-RayPayloadKHR-04698"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr("RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
+                  "ClosestHitKHR, and MissKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, HitAttributeStore) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "HitAttributeKHR", true)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("IntersectionKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else if (execution_model.compare("AnyHitKHR") == 0 ||
+             execution_model.compare("ClosestHitKHR") == 0) {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04703"));
+    EXPECT_THAT(getDiagnosticString(),
+                HasSubstr("HitAttributeKHR Storage Class variables are read "
+                          "only with AnyHitKHR and ClosestHitKHR"));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04701"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr(
+            "HitAttributeKHR Storage Class is limited to IntersectionKHR, "
+            "AnyHitKHR, sand ClosestHitKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, HitAttributeLoad) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "HitAttributeKHR", false)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("IntersectionKHR") == 0 ||
+      execution_model.compare("AnyHitKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04701"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr(
+            "HitAttributeKHR Storage Class is limited to IntersectionKHR, "
+            "AnyHitKHR, sand ClosestHitKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, IncomingRayPayloadStore) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "IncomingRayPayloadKHR", true)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("AnyHitKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr("IncomingRayPayloadKHR Storage Class is limited to "
+                  "AnyHitKHR, ClosestHitKHR, and MissKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, IncomingRayPayloadLoad) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(GenerateExecutionModelCode(execution_model,
+                                                 "IncomingRayPayloadKHR", false)
+                          .c_str(),
+                      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("AnyHitKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(getDiagnosticString(),
+                AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699"));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr("IncomingRayPayloadKHR Storage Class is limited to "
+                  "AnyHitKHR, ClosestHitKHR, and MissKHR execution model"));
+  }
+}
+
+TEST_P(ValidateStorageExecutionModel, ShaderRecordBufferStore) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(
+      GenerateExecutionModelCode(execution_model, "ShaderRecordBufferKHR", true)
+          .c_str(),
+      SPV_ENV_VULKAN_1_2);
+  ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("ShaderRecordBufferKHR Storage Class variables are read only"));
+}
+
+TEST_P(ValidateStorageExecutionModel, ShaderRecordBufferLoad) {
+  std::string execution_model = GetParam();
+  CompileSuccessfully(GenerateExecutionModelCode(execution_model,
+                                                 "ShaderRecordBufferKHR", false)
+                          .c_str(),
+                      SPV_ENV_VULKAN_1_2);
+  if (execution_model.compare("RayGenerationKHR") == 0 ||
+      execution_model.compare("IntersectionKHR") == 0 ||
+      execution_model.compare("AnyHitKHR") == 0 ||
+      execution_model.compare("ClosestHitKHR") == 0 ||
+      execution_model.compare("CallableKHR") == 0 ||
+      execution_model.compare("MissKHR") == 0) {
+    ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+  } else {
+    ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+    EXPECT_THAT(
+        getDiagnosticString(),
+        HasSubstr("ShaderRecordBufferKHR Storage Class is limited to "
+                  "RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
+                  "ClosestHitKHR, CallableKHR, and MissKHR execution model"));
+  }
+}
+
 INSTANTIATE_TEST_SUITE_P(MatrixExecutionModel, ValidateStorageExecutionModel,
                          ::testing::Values("RayGenerationKHR",
                                            "IntersectionKHR", "AnyHitKHR",
                                            "ClosestHitKHR", "MissKHR",
-                                           "CallableKHR"));
+                                           "CallableKHR", "GLCompute"));
 
 }  // namespace
 }  // namespace val