Ensure that entry point names are unique for WebGPU (#2281)

Fixes #2275
This commit is contained in:
Ryan Harrison 2019-01-14 13:52:28 -05:00 committed by GitHub
parent 6958d11bc2
commit 16a0da370b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 1 deletions

View File

@ -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;

View File

@ -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