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:
Ryan Harrison 2018-11-22 12:52:04 -05:00 committed by GitHub
parent 981763ec74
commit 7a3493e887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 222 additions and 0 deletions

View File

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

View File

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