spirv-val: Add OpConvertUToAccelerationStructureKHR (#4838)

diff --git a/source/val/validate_conversion.cpp b/source/val/validate_conversion.cpp
index b4e39cf..dc6b151 100644
--- a/source/val/validate_conversion.cpp
+++ b/source/val/validate_conversion.cpp
@@ -534,6 +534,24 @@
       break;
     }
 
+    case SpvOpConvertUToAccelerationStructureKHR: {
+      if (!_.IsAccelerationStructureType(result_type)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Expected Result Type to be a Acceleration Structure: "
+               << spvOpcodeString(opcode);
+      }
+
+      const uint32_t input_type = _.GetOperandTypeId(inst, 2);
+      if (!input_type || !_.IsUnsigned64BitHandle(input_type)) {
+        return _.diag(SPV_ERROR_INVALID_DATA, inst)
+               << "Expected 64-bit uint scalar or 2-component 32-bit uint "
+                  "vector as input: "
+               << spvOpcodeString(opcode);
+      }
+
+      break;
+    }
+
     default:
       break;
   }
diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp
index 3bc15ca..5acc21e 100644
--- a/source/val/validate_misc.cpp
+++ b/source/val/validate_misc.cpp
@@ -59,10 +59,7 @@
   // a vector of two - components of 32 -
   // bit unsigned integer type
   const uint32_t result_type = inst->type_id();
-  if (!(_.IsUnsignedIntScalarType(result_type) &&
-        _.GetBitWidth(result_type) == 64) &&
-      !(_.IsUnsignedIntVectorType(result_type) &&
-        _.GetDimension(result_type) == 2 && _.GetBitWidth(result_type) == 32)) {
+  if (!_.IsUnsigned64BitHandle(result_type)) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Value to be a "
                                                    "vector of two components"
                                                    " of unsigned integer"
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 77e1573..339f79a 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -965,6 +965,11 @@
   return true;
 }
 
+bool ValidationState_t::IsAccelerationStructureType(uint32_t id) const {
+  const Instruction* inst = FindDef(id);
+  return inst && inst->opcode() == SpvOpTypeAccelerationStructureKHR;
+}
+
 bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
   const Instruction* inst = FindDef(id);
   return inst && inst->opcode() == SpvOpTypeCooperativeMatrixNV;
@@ -985,6 +990,13 @@
   return IsUnsignedIntScalarType(FindDef(id)->word(2));
 }
 
+// Either a 32 bit 2-component uint vector or a 64 bit uint scalar
+bool ValidationState_t::IsUnsigned64BitHandle(uint32_t id) const {
+  return ((IsUnsignedIntScalarType(id) && GetBitWidth(id) == 64) ||
+          (IsUnsignedIntVectorType(id) && GetDimension(id) == 2 &&
+           GetBitWidth(id) == 32));
+}
+
 spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
     const Instruction* inst, uint32_t m1, uint32_t m2) {
   const auto m1_type = FindDef(m1);
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index 2178046..745fd02 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -592,10 +592,12 @@
   bool IsBoolVectorType(uint32_t id) const;
   bool IsBoolScalarOrVectorType(uint32_t id) const;
   bool IsPointerType(uint32_t id) const;
+  bool IsAccelerationStructureType(uint32_t id) const;
   bool IsCooperativeMatrixType(uint32_t id) const;
   bool IsFloatCooperativeMatrixType(uint32_t id) const;
   bool IsIntCooperativeMatrixType(uint32_t id) const;
   bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const;
+  bool IsUnsigned64BitHandle(uint32_t id) const;
 
   // Returns true if |id| is a type id that contains |type| (or integer or
   // floating point type) of |width| bits.
diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp
index 94bd27d..f6f37b3 100644
--- a/test/val/val_conversion_test.cpp
+++ b/test/val/val_conversion_test.cpp
@@ -1641,6 +1641,131 @@
                 "integer type to have a 64-bit width for Vulkan environment."));
 }
 
+TEST_F(ValidateConversion, ConvertUToAccelerationStructureU32Vec2) {
+  const std::string extensions = R"(
+OpCapability RayQueryKHR
+OpExtension "SPV_KHR_ray_query"
+)";
+  const std::string types = R"(
+%u32vec2ptr_func = OpTypePointer Function %u32vec2
+%typeAS = OpTypeAccelerationStructureKHR
+)";
+  const std::string body = R"(
+%asHandle = OpVariable %u32vec2ptr_func Function
+%load = OpLoad %u32vec2 %asHandle
+%val = OpConvertUToAccelerationStructureKHR %typeAS %load
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extensions, "", types).c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, ConvertUToAccelerationStructureSuccessU64) {
+  const std::string extensions = R"(
+OpCapability RayQueryKHR
+OpExtension "SPV_KHR_ray_query"
+)";
+  const std::string types = R"(
+%u64_func = OpTypePointer Function %u64
+%typeAS = OpTypeAccelerationStructureKHR
+)";
+  const std::string body = R"(
+%asHandle = OpVariable %u64_func Function
+%load = OpLoad %u64 %asHandle
+%val = OpConvertUToAccelerationStructureKHR %typeAS %load
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extensions, "", types).c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, ConvertUToAccelerationStructureResult) {
+  const std::string extensions = R"(
+OpCapability RayQueryKHR
+OpExtension "SPV_KHR_ray_query"
+)";
+  const std::string types = R"(
+%u32vec2ptr_func = OpTypePointer Function %u32vec2
+%typeRQ = OpTypeRayQueryKHR
+)";
+  const std::string body = R"(
+%asHandle = OpVariable %u32vec2ptr_func Function
+%load = OpLoad %u32vec2 %asHandle
+%val = OpConvertUToAccelerationStructureKHR %typeRQ %load
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extensions, "", types).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected Result Type to be a Acceleration Structure"));
+}
+
+TEST_F(ValidateConversion, ConvertUToAccelerationStructureU32) {
+  const std::string extensions = R"(
+OpCapability RayQueryKHR
+OpExtension "SPV_KHR_ray_query"
+)";
+  const std::string types = R"(
+%u32ptr_func = OpTypePointer Function %u32
+%typeAS = OpTypeAccelerationStructureKHR
+)";
+  const std::string body = R"(
+%asHandle = OpVariable %u32ptr_func Function
+%load = OpLoad %u32 %asHandle
+%val = OpConvertUToAccelerationStructureKHR %typeAS %load
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extensions, "", types).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected 64-bit uint scalar or 2-component 32-bit "
+                        "uint vector as input"));
+}
+
+TEST_F(ValidateConversion, ConvertUToAccelerationStructureS64) {
+  const std::string extensions = R"(
+OpCapability RayQueryKHR
+OpExtension "SPV_KHR_ray_query"
+)";
+  const std::string types = R"(
+%s64ptr_func = OpTypePointer Function %s64
+%typeAS = OpTypeAccelerationStructureKHR
+)";
+  const std::string body = R"(
+%asHandle = OpVariable %s64ptr_func Function
+%load = OpLoad %s64 %asHandle
+%val = OpConvertUToAccelerationStructureKHR %typeAS %load
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extensions, "", types).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected 64-bit uint scalar or 2-component 32-bit "
+                        "uint vector as input"));
+}
+
+TEST_F(ValidateConversion, ConvertUToAccelerationStructureS32Vec2) {
+  const std::string extensions = R"(
+OpCapability RayQueryKHR
+OpExtension "SPV_KHR_ray_query"
+)";
+  const std::string types = R"(
+%s32vec2ptr_func = OpTypePointer Function %s32vec2
+%typeAS = OpTypeAccelerationStructureKHR
+)";
+  const std::string body = R"(
+%asHandle = OpVariable %s32vec2ptr_func Function
+%load = OpLoad %s32vec2 %asHandle
+%val = OpConvertUToAccelerationStructureKHR %typeAS %load
+)";
+
+  CompileSuccessfully(GenerateShaderCode(body, extensions, "", types).c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Expected 64-bit uint scalar or 2-component 32-bit "
+                        "uint vector as input"));
+}
+
 using ValidateSmallConversions = spvtest::ValidateBase<std::string>;
 
 CodeGenerator GetSmallConversionsCodeGenerator() {