mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-25 17:21:06 +00:00
Make sure that initialized variable have correct storage class (#2092)
Make sure that initialized variable have correct storage class For WebGPU and Vulkan environments, variables must have the storage class; Output, Private, or Function, if they have an initializer. Fixes #2071
This commit is contained in:
parent
981763ec74
commit
7a3493e887
@ -389,6 +389,34 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
// WebGPU & Vulkan Appendix A: Check that if contains initializer, then
|
||||
// storage class is Output, Private, or Function.
|
||||
if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput &&
|
||||
storage_class != SpvStorageClassPrivate &&
|
||||
storage_class != SpvStorageClassFunction) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> '" << _.getIdName(inst->id())
|
||||
<< "', has a disallowed initializer & storage class "
|
||||
<< "combination.\n"
|
||||
<< "From Vulkan spec, Appendix A:\n"
|
||||
<< "Variable declarations that include initializers must have "
|
||||
<< "one of the following storage classes: Output, Private, or "
|
||||
<< "Function";
|
||||
}
|
||||
|
||||
if (spvIsWebGPUEnv(_.context()->target_env)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> '" << _.getIdName(inst->id())
|
||||
<< "', has a disallowed initializer & storage class "
|
||||
<< "combination.\n"
|
||||
<< "From WebGPU execution environment spec:\n"
|
||||
<< "Variable declarations that include initializers must have "
|
||||
<< "one of the following storage classes: Output, Private, or "
|
||||
<< "Function";
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -349,6 +349,200 @@ OpFunctionEnd
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUInitializerWithOutputStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Output %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%1 = OpVariable %float_ptr Output %init_val
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUInitializerWithFunctionStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Function %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
%2 = OpVariable %float_ptr Function %init_val
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUInitializerWithPrivateStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Private %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%1 = OpVariable %float_ptr Private %init_val
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUInitializerWithDisallowedStorageClassesBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Uniform %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%1 = OpVariable %float_ptr Uniform %init_val
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpVariable, <id> '5', has a disallowed initializer & storage class "
|
||||
"combination.\n"
|
||||
"From WebGPU execution environment spec:\n"
|
||||
"Variable declarations that include initializers must have one of "
|
||||
"the following storage classes: Output, Private, or Function\n"
|
||||
" %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Output %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%1 = OpVariable %float_ptr Output %init_val
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanInitializerWithFunctionStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Function %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
%2 = OpVariable %float_ptr Function %init_val
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanInitializerWithPrivateStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Private %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%1 = OpVariable %float_ptr Private %init_val
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanInitializerWithDisallowedStorageClassesBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Input %float
|
||||
%init_val = OpConstant %float 1.0
|
||||
%1 = OpVariable %float_ptr Input %init_val
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpVariable, <id> '5', has a disallowed initializer & storage class "
|
||||
"combination.\n"
|
||||
"From Vulkan spec, Appendix A:\n"
|
||||
"Variable declarations that include initializers must have one of "
|
||||
"the following storage classes: Output, Private, or Function\n "
|
||||
"%5 = OpVariable %_ptr_Input_float Input %float_1\n"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user