spirv-val: Consider target env for OpReadClockKHR scope (#5681)

The Scope operand of `OpReadClockKHR` was always validated using the
Vulkan environment rules, which only allow `Subgroup` or `Device`.
For the OpenCL environment, `Workgroup` is also a valid Scope, so
`Workgroup` should not be rejected in the universal environment.

Guard the existing Scope check behind `spvIsVulkanEnv` and add a new
Scope check for the OpenCL environment.

Signed-off-by: Sven van Haastregt <sven.vanhaastregt@arm.com>
This commit is contained in:
Sven van Haastregt 2024-05-21 19:02:17 +02:00 committed by GitHub
parent e4b1a48aab
commit e2646f5e95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 70 additions and 5 deletions

View File

@ -50,10 +50,22 @@ spv_result_t ValidateShaderClock(ValidationState_t& _,
bool is_int32 = false, is_const_int32 = false;
uint32_t value = 0;
std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope);
if (is_const_int32 && spv::Scope(value) != spv::Scope::Subgroup &&
spv::Scope(value) != spv::Scope::Device) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4652) << "Scope must be Subgroup or Device";
if (is_const_int32) {
spv::Scope scope_val{value};
if (spvIsVulkanEnv(_.context()->target_env)) {
if (scope_val != spv::Scope::Subgroup &&
scope_val != spv::Scope::Device) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4652) << "Scope must be Subgroup or Device";
}
} else if (spvIsOpenCLEnv(_.context()->target_env)) {
if (scope_val != spv::Scope::Workgroup &&
scope_val != spv::Scope::Subgroup &&
scope_val != spv::Scope::Device) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Scope must be Subgroup, Workgroup, or Device";
}
}
}
// Result Type must be a 64 - bit unsigned integer type or

View File

@ -222,7 +222,7 @@ OpReturn
OpFunctionEnd)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Scope must be Subgroup or Device"));
}
@ -251,6 +251,59 @@ OpFunctionEnd)";
HasSubstr("Scope must be Subgroup or Device"));
}
std::string GenKernelClockSpirv(const std::string& scope) {
const std::string s = R"(
OpCapability Kernel
OpCapability Addresses
OpCapability Int64
OpCapability ShaderClockKHR
OpExtension "SPV_KHR_shader_clock"
OpMemoryModel Physical32 OpenCL
OpEntryPoint Kernel %main "main"
OpExecutionMode %main ContractionOff
OpSource OpenCL_C 200000
OpName %main "main"
OpName %time1 "time1"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%ulong = OpTypeInt 64 0
%uint = OpTypeInt 32 0
%_ptr_Function_ulong = OpTypePointer Function %ulong
%scope = OpConstant %uint )" +
scope + R"(
%main = OpFunction %void None %3
%5 = OpLabel
%time1 = OpVariable %_ptr_Function_ulong Function
%11 = OpReadClockKHR %ulong %scope
OpStore %time1 %11
OpReturn
OpFunctionEnd
)";
return s;
}
TEST_F(ValidateMisc, KernelClockScopeDevice) {
CompileSuccessfully(GenKernelClockSpirv("1"), SPV_ENV_OPENCL_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
}
TEST_F(ValidateMisc, KernelClockScopeWorkgroup) {
CompileSuccessfully(GenKernelClockSpirv("2"), SPV_ENV_OPENCL_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
}
TEST_F(ValidateMisc, KernelClockScopeSubgroup) {
CompileSuccessfully(GenKernelClockSpirv("3"), SPV_ENV_OPENCL_1_2);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
}
TEST_F(ValidateMisc, KernelClockScopeInvalid) {
CompileSuccessfully(GenKernelClockSpirv("0"), SPV_ENV_OPENCL_1_2);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Scope must be Subgroup, Workgroup, or Device"));
}
TEST_F(ValidateMisc, UndefVoid) {
const std::string spirv = R"(
OpCapability Shader