mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-24 00:40:14 +00:00
Ensure that entry point names are unique for WebGPU (#2281)
Fixes #2275
This commit is contained in:
parent
6958d11bc2
commit
16a0da370b
@ -169,6 +169,57 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
|
||||
<< id_str.substr(0, id_str.size() - 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> CalculateNamesForEntryPoint(ValidationState_t& _,
|
||||
const uint32_t id) {
|
||||
auto id_descriptions = _.entry_point_descriptions(id);
|
||||
auto id_names = std::vector<std::string>();
|
||||
id_names.reserve((id_descriptions.size()));
|
||||
|
||||
for (auto description : id_descriptions) id_names.push_back(description.name);
|
||||
|
||||
return id_names;
|
||||
}
|
||||
|
||||
spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _,
|
||||
const uint32_t id) {
|
||||
auto id_names = CalculateNamesForEntryPoint(_, id);
|
||||
const auto names =
|
||||
std::unordered_set<std::string>(id_names.begin(), id_names.end());
|
||||
|
||||
if (id_names.size() != names.size()) {
|
||||
std::sort(id_names.begin(), id_names.end());
|
||||
for (size_t i = 0; i < id_names.size() - 1; i++) {
|
||||
if (id_names[i] == id_names[i + 1]) {
|
||||
return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
|
||||
<< "Entry point name \"" << id_names[i]
|
||||
<< "\" is not unique, which is not allow in WebGPU env.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto other_id : _.entry_points()) {
|
||||
if (other_id == id) continue;
|
||||
const auto other_id_names = CalculateNamesForEntryPoint(_, other_id);
|
||||
for (const auto other_id_name : other_id_names) {
|
||||
if (names.find(other_id_name) != names.end()) {
|
||||
return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
|
||||
<< "Entry point name \"" << other_id_name
|
||||
<< "\" is not unique, which is not allow in WebGPU env.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) {
|
||||
for (const auto id : _.entry_points()) {
|
||||
auto result = ValidateEntryPointNameUnique(_, id);
|
||||
if (result != SPV_SUCCESS) return result;
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
// Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
|
||||
// SPIRV spec:
|
||||
// * There is at least one OpEntryPoint instruction, unless the Linkage
|
||||
@ -177,7 +228,7 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
|
||||
// OpFunctionCall instruction.
|
||||
//
|
||||
// Additionally enforces that entry points for Vulkan and WebGPU should not have
|
||||
// recursion.
|
||||
// recursion. And that entry names should be unique for WebGPU.
|
||||
spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
||||
_.ComputeFunctionToEntryPointMapping();
|
||||
_.ComputeRecursiveEntryPoints();
|
||||
@ -206,6 +257,12 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
||||
<< "Entry points may not have a call graph with cycles.";
|
||||
}
|
||||
}
|
||||
|
||||
// For WebGPU all entry point names must be unique.
|
||||
if (spvIsWebGPUEnv(_.context()->target_env)) {
|
||||
const auto result = ValidateEntryPointNamesUnique(_);
|
||||
if (result != SPV_SUCCESS) return result;
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
|
@ -306,6 +306,54 @@ TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) {
|
||||
"called.\n %9 = OpFunctionCall %_struct_5 %10\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidationStateTest,
|
||||
CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) {
|
||||
std::string spirv = std::string(kVulkanMemoryHeader) + R"(
|
||||
OpEntryPoint Fragment %func_1 "main"
|
||||
OpEntryPoint Vertex %func_2 "main"
|
||||
OpExecutionMode %func_1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%void_f = OpTypeFunction %void
|
||||
%func_1 = OpFunction %void None %void_f
|
||||
%label_1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func_2 = OpFunction %void None %void_f
|
||||
%label_2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Entry point name \"main\" is not unique, which is not allow "
|
||||
"in WebGPU env.\n %1 = OpFunction %void None %4\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) {
|
||||
std::string spirv = std::string(kVulkanMemoryHeader) + R"(
|
||||
OpEntryPoint GLCompute %func_1 "main"
|
||||
OpEntryPoint Vertex %func_1 "main"
|
||||
%void = OpTypeVoid
|
||||
%void_f = OpTypeFunction %void
|
||||
%func_1 = OpFunction %void None %void_f
|
||||
%label_1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Entry point name \"main\" is not unique, which is not allow "
|
||||
"in WebGPU env.\n %1 = OpFunction %void None %3\n"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user