Validate OpenCL environment rules for OpTypeImage (#2606)

It is currently not possible to use an Image Format that is
not Unknown without requiring a capability forbidden by the
OpenCL environment. As such the validation of Image Format
currently leans on capability validation entirely.

Fixes #2592.

Signed-off-by: Kevin Petit <kevin.petit@arm.com>
This commit is contained in:
Kévin Petit 2019-05-21 14:17:50 +01:00 committed by alan-baker
parent 47741f0504
commit 9f035269d6
4 changed files with 135 additions and 1 deletions

View File

@ -718,6 +718,11 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< "Expected Sampled Type to be a 32-bit int or float "
"scalar type for Vulkan environment";
}
} else if (spvIsOpenCLEnv(_.context()->target_env)) {
if (!_.IsVoidType(info.sampled_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Sampled Type must be OpTypeVoid in the OpenCL environment.";
}
} else {
const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type);
if (sampled_type_opcode != SpvOpTypeVoid &&
@ -741,16 +746,39 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
<< "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)";
}
if (spvIsOpenCLEnv(_.context()->target_env)) {
if ((info.arrayed == 1) && (info.dim != SpvDim1D) &&
(info.dim != SpvDim2D)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "In the OpenCL environment, Arrayed may only be set to 1 "
<< "when Dim is either 1D or 2D.";
}
}
if (info.multisampled > 1) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Invalid MS " << info.multisampled << " (must be 0 or 1)";
}
if (spvIsOpenCLEnv(_.context()->target_env)) {
if (info.multisampled != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "MS must be 0 in the OpenCL environement.";
}
}
if (info.sampled > 2) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)";
}
if (spvIsOpenCLEnv(_.context()->target_env)) {
if (info.sampled != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Sampled must be 0 in the OpenCL environment.";
}
}
if (info.dim == SpvDimSubpassData) {
if (info.sampled != 2) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
@ -763,7 +791,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
}
}
// Format and Access Qualifier are checked elsewhere.
// Format and Access Qualifier are also checked elsewhere.
if (spvIsOpenCLEnv(_.context()->target_env)) {
if (info.access_qualifier == SpvAccessQualifierMax) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "In the OpenCL environment, the optional Access Qualifier"
<< " must be present.";
}
}
return SPV_SUCCESS;
}

View File

@ -691,6 +691,12 @@ uint32_t ValidationState_t::GetBitWidth(uint32_t id) const {
return 0;
}
bool ValidationState_t::IsVoidType(uint32_t id) const {
const Instruction* inst = FindDef(id);
assert(inst);
return inst->opcode() == SpvOpTypeVoid;
}
bool ValidationState_t::IsFloatScalarType(uint32_t id) const {
const Instruction* inst = FindDef(id);
assert(inst);

View File

@ -548,6 +548,7 @@ class ValidationState_t {
// Returns true iff |id| is a type corresponding to the name of the function.
// Only works for types not for objects.
bool IsVoidType(uint32_t id) const;
bool IsFloatScalarType(uint32_t id) const;
bool IsFloatVectorType(uint32_t id) const;
bool IsFloatScalarOrVectorType(uint32_t id) const;

View File

@ -56,6 +56,97 @@ TEST_F(ValidateOpenCL, NonOpenCLMemoryModelBad) {
"\n OpMemoryModel Physical32 GLSL450\n"));
}
TEST_F(ValidateOpenCL, NonVoidSampledTypeImageBad) {
std::string spirv = R"(
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical32 OpenCL
%1 = OpTypeInt 32 0
%2 = OpTypeImage %1 2D 0 0 0 0 Unknown ReadOnly
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Sampled Type must be OpTypeVoid in the OpenCL environment."
"\n %2 = OpTypeImage %uint 2D 0 0 0 0 Unknown ReadOnly\n"));
}
TEST_F(ValidateOpenCL, NonZeroMSImageBad) {
std::string spirv = R"(
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical32 OpenCL
%1 = OpTypeVoid
%2 = OpTypeImage %1 2D 0 0 1 0 Unknown ReadOnly
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("MS must be 0 in the OpenCL environement."
"\n %2 = OpTypeImage %void 2D 0 0 1 0 Unknown ReadOnly\n"));
}
TEST_F(ValidateOpenCL, Non1D2DArrayedImageBad) {
std::string spirv = R"(
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical32 OpenCL
%1 = OpTypeVoid
%2 = OpTypeImage %1 3D 0 1 0 0 Unknown ReadOnly
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("In the OpenCL environment, Arrayed may only be set to 1 "
"when Dim is either 1D or 2D."
"\n %2 = OpTypeImage %void 3D 0 1 0 0 Unknown ReadOnly\n"));
}
TEST_F(ValidateOpenCL, NonZeroSampledImageBad) {
std::string spirv = R"(
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical32 OpenCL
%1 = OpTypeVoid
%2 = OpTypeImage %1 3D 0 0 0 1 Unknown ReadOnly
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Sampled must be 0 in the OpenCL environment."
"\n %2 = OpTypeImage %void 3D 0 0 0 1 Unknown ReadOnly\n"));
}
TEST_F(ValidateOpenCL, NoAccessQualifierImageBad) {
std::string spirv = R"(
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical32 OpenCL
%1 = OpTypeVoid
%2 = OpTypeImage %1 3D 0 0 0 0 Unknown
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("In the OpenCL environment, the optional "
"Access Qualifier must be present."
"\n %2 = OpTypeImage %void 3D 0 0 0 0 Unknown\n"));
}
} // namespace
} // namespace val
} // namespace spvtools