Validator: Validate OpImageTexelPointer (#487)

Checked all instructions whose object is OpTypeSampledImage or
OpTypeImage as suggested in #487. OpImageTexelPointer instruction
is missing and others look good. This commit adds only
OpImageTexelPointer.
This commit is contained in:
Jaebaek Seo 2018-09-21 22:55:01 -04:00
parent a78fa0978d
commit 4b4bd4c53a
2 changed files with 274 additions and 0 deletions

View File

@ -793,6 +793,110 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
return SPV_SUCCESS;
}
spv_result_t ValidateImageTexelPointer(ValidationState_t& _,
const Instruction* inst) {
const auto result_type = _.FindDef(inst->type_id());
if (result_type->opcode() != SpvOpTypePointer) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Result Type to be OpTypePointer";
}
const auto storage_class = result_type->GetOperandAs<uint32_t>(1);
if (storage_class != SpvStorageClassImage) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Result Type to be OpTypePointer whose Storage Class "
"operand is Image";
}
const auto ptr_type = result_type->GetOperandAs<uint32_t>(2);
const auto ptr_opcode = _.GetIdOpcode(ptr_type);
if (ptr_opcode != SpvOpTypeInt && ptr_opcode != SpvOpTypeFloat &&
ptr_opcode != SpvOpTypeVoid) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Result Type to be OpTypePointer whose Type operand "
"must be a scalar numerical type or OpTypeVoid";
}
const auto image_ptr = _.FindDef(_.GetOperandTypeId(inst, 2));
if (!image_ptr || image_ptr->opcode() != SpvOpTypePointer) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image to be OpTypePointer";
}
const auto image_type = image_ptr->GetOperandAs<uint32_t>(2);
if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image to be OpTypePointer with Type OpTypeImage";
}
ImageTypeInfo info;
if (!GetImageTypeInfo(_, image_type, &info)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Corrupt image type definition";
}
if (info.sampled_type != ptr_type) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image 'Sampled Type' to be the same as the Type "
"pointed to by Result Type";
}
if (info.dim == SpvDimSubpassData) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Image Dim SubpassData cannot be used with OpImageTexelPointer";
}
const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
if (!coord_type || !_.IsIntScalarOrVectorType(coord_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Coordinate to be integer scalar or vector";
}
uint32_t expected_coord_size = 0;
if (info.arrayed == 0) {
expected_coord_size = GetPlaneCoordSize(info);
} else if (info.arrayed == 1) {
switch (info.dim) {
case SpvDim1D:
expected_coord_size = 2;
break;
case SpvDimCube:
case SpvDim2D:
expected_coord_size = 3;
break;
default:
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Image 'Dim' must be one of 1D, 2D, or Cube when "
"Arrayed is 1";
break;
}
}
const uint32_t actual_coord_size = _.GetDimension(coord_type);
if (expected_coord_size != actual_coord_size) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Coordinate to have " << expected_coord_size
<< " components, but given " << actual_coord_size;
}
const uint32_t sample_type = _.GetOperandTypeId(inst, 4);
if (!sample_type || !_.IsIntScalarType(sample_type)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Sample to be integer scalar";
}
if (info.multisampled == 0) {
uint64_t ms = 0;
if (!_.GetConstantValUint64(inst->GetOperandAs<uint32_t>(4), &ms) ||
ms != 0) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected Sample for Image with MS 0 to be a valid <id> for "
"the value 0";
}
}
return SPV_SUCCESS;
}
spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) {
const SpvOp opcode = inst->opcode();
uint32_t actual_result_type = 0;
@ -1580,6 +1684,8 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) {
return ValidateTypeSampledImage(_, inst);
case SpvOpSampledImage:
return ValidateSampledImage(_, inst);
case SpvOpImageTexelPointer:
return ValidateImageTexelPointer(_, inst);
case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleExplicitLod:

View File

@ -46,6 +46,7 @@ OpCapability ImageQuery
OpCapability Int64
OpCapability Float64
OpCapability SparseResidency
OpCapability ImageBuffer
)";
if (env == SPV_ENV_UNIVERSAL_1_0) {
@ -209,6 +210,22 @@ OpCapability SparseResidency
%type_sampler = OpTypeSampler
%ptr_sampler = OpTypePointer UniformConstant %type_sampler
%uniform_sampler = OpVariable %ptr_sampler UniformConstant
%type_image_u32_buffer_0002_r32ui = OpTypeImage %u32 Buffer 0 0 0 2 R32ui
%ptr_Image_u32 = OpTypePointer Image %u32
%ptr_image_u32_buffer_0002_r32ui = OpTypePointer Private %type_image_u32_buffer_0002_r32ui
%private_image_u32_buffer_0002_r32ui = OpVariable %ptr_image_u32_buffer_0002_r32ui Private
%ptr_Image_u32arr4 = OpTypePointer Image %u32arr4
%type_image_u32_spd_0002 = OpTypeImage %u32 SubpassData 0 0 0 2 Unknown
%ptr_image_u32_spd_0002 = OpTypePointer Private %type_image_u32_spd_0002
%private_image_u32_spd_0002 = OpVariable %ptr_image_u32_spd_0002 Private
%type_image_f32_buffer_0002_r32ui = OpTypeImage %f32 Buffer 0 0 0 2 R32ui
%ptr_Image_f32 = OpTypePointer Image %f32
%ptr_image_f32_buffer_0002_r32ui = OpTypePointer Private %type_image_f32_buffer_0002_r32ui
%private_image_f32_buffer_0002_r32ui = OpVariable %ptr_image_f32_buffer_0002_r32ui Private
)";
if (env == SPV_ENV_UNIVERSAL_1_0) {
@ -593,6 +610,157 @@ TEST_F(ValidateImage, SampledImageNotSampler) {
HasSubstr("Expected Sampler to be of type OpTypeSampler"));
}
TEST_F(ValidateImage, ImageTexelPointerSuccess) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateImage, ImageTexelPointerResultTypeNotPointer) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %type_image_u32_buffer_0002_r32ui %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type to be OpTypePointer"));
}
TEST_F(ValidateImage, ImageTexelPointerResultTypeNotImageClass) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_image_f32_cube_0101 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Result Type to be OpTypePointer whose "
"Storage Class operand is Image"));
}
TEST_F(ValidateImage, ImageTexelPointerResultTypeNotNumericNorVoid) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32arr4 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Expected Result Type to be OpTypePointer whose Type operand "
"must be a scalar numerical type or OpTypeVoid"));
}
TEST_F(ValidateImage, ImageTexelPointerImageNotResultTypePointer) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %type_image_f32_buffer_0002_r32ui %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Image to be OpTypePointer"));
}
TEST_F(ValidateImage, ImageTexelPointerImageNotImage) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_sampler %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Expected Image to be OpTypePointer with Type OpTypeImage"));
}
TEST_F(ValidateImage, ImageTexelPointerImageSampledNotResultType) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_f32_cube_0101 %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Image 'Sampled Type' to be the same as the "
"Type pointed to by Result Type"));
}
TEST_F(ValidateImage, ImageTexelPointerImageDimSubpassDataBad) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_spd_0002 %u32_0 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Image Dim SubpassData cannot be used with OpImageTexelPointer"));
}
TEST_F(ValidateImage, ImageTexelPointerImageCoordTypeBad) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_f32 %private_image_f32_buffer_0002_r32ui %f32_0 %f32_0
%sum = OpAtomicIAdd %f32 %texel_ptr %f32_1 %f32_0 %f32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Coordinate to be integer scalar or vector"));
}
TEST_F(ValidateImage, ImageTexelPointerImageCoordSizeBad) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0000 %u32vec3_012 %u32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Expected Coordinate to have 2 components, but given 3"));
}
TEST_F(ValidateImage, ImageTexelPointerSampleNotIntScalar) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %f32_0
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Sample to be integer scalar"));
}
TEST_F(ValidateImage, ImageTexelPointerSampleNotZeroForImageWithMSZero) {
const std::string body = R"(
%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_1
%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1
)";
CompileSuccessfully(GenerateShaderCode(body).c_str());
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Expected Sample for Image with MS 0 to be a valid "
"<id> for the value 0"));
}
TEST_F(ValidateImage, SampleImplicitLodSuccess) {
const std::string body = R"(
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001