spirv-fuzz: Add image sample unused components transformation (#3439)

Fixes #3375.
This commit is contained in:
André Perez 2020-07-08 13:07:04 -03:00 committed by GitHub
parent 7afbc0c8be
commit daa3b47ed4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 734 additions and 0 deletions

View File

@ -46,6 +46,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_pass_add_equation_instructions.h
fuzzer_pass_add_function_calls.h
fuzzer_pass_add_global_variables.h
fuzzer_pass_add_image_sample_unused_components.h
fuzzer_pass_add_loads.h
fuzzer_pass_add_local_variables.h
fuzzer_pass_add_no_contraction_decorations.h
@ -96,6 +97,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_add_function.h
transformation_add_global_undef.h
transformation_add_global_variable.h
transformation_add_image_sample_unused_components.h
transformation_add_local_variable.h
transformation_add_no_contraction_decoration.h
transformation_add_parameter.h
@ -158,6 +160,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_pass_add_equation_instructions.cpp
fuzzer_pass_add_function_calls.cpp
fuzzer_pass_add_global_variables.cpp
fuzzer_pass_add_image_sample_unused_components.cpp
fuzzer_pass_add_loads.cpp
fuzzer_pass_add_local_variables.cpp
fuzzer_pass_add_no_contraction_decorations.cpp
@ -207,6 +210,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_add_function.cpp
transformation_add_global_undef.cpp
transformation_add_global_variable.cpp
transformation_add_image_sample_unused_components.cpp
transformation_add_local_variable.cpp
transformation_add_no_contraction_decoration.cpp
transformation_add_parameter.cpp

View File

@ -30,6 +30,7 @@
#include "source/fuzz/fuzzer_pass_add_equation_instructions.h"
#include "source/fuzz/fuzzer_pass_add_function_calls.h"
#include "source/fuzz/fuzzer_pass_add_global_variables.h"
#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
#include "source/fuzz/fuzzer_pass_add_loads.h"
#include "source/fuzz/fuzzer_pass_add_local_variables.h"
#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
@ -224,6 +225,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
MaybeAddPass<FuzzerPassAddGlobalVariables>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddImageSampleUnusedComponents>(
&passes, ir_context.get(), &transformation_context, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(),
&transformation_context, &fuzzer_context,
transformation_sequence_out);

View File

@ -34,6 +34,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
const std::pair<uint32_t, uint32_t> kChanceOfAddingEquationInstruction = {5,
90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingGlobalVariable = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingImageSampleUnusedComponents =
{20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingLoad = {5, 50};
const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
@ -137,6 +139,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
chance_of_adding_global_variable_ =
ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable);
chance_of_adding_load_ = ChooseBetweenMinAndMax(kChanceOfAddingLoad);
chance_of_adding_image_sample_unused_components_ =
ChooseBetweenMinAndMax(kChanceOfAddingImageSampleUnusedComponents);
chance_of_adding_local_variable_ =
ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable);
chance_of_adding_matrix_type_ =

View File

@ -128,6 +128,9 @@ class FuzzerContext {
uint32_t GetChanceOfAddingGlobalVariable() {
return chance_of_adding_global_variable_;
}
uint32_t GetChanceOfAddingImageSampleUnusedComponents() {
return chance_of_adding_image_sample_unused_components_;
}
uint32_t GetChanceOfAddingLoad() { return chance_of_adding_load_; }
uint32_t GetChanceOfAddingLocalVariable() {
return chance_of_adding_local_variable_;
@ -268,6 +271,11 @@ class FuzzerContext {
// Ensure that the array size is non-zero.
return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
}
uint32_t GetRandomUnusedComponentCountForImageSample(
uint32_t max_unused_component_count) {
// Ensure that the number of unused components is non-zero.
return random_generator_->RandomUint32(max_unused_component_count) + 1;
}
bool GoDeeperInConstantObfuscation(uint32_t depth) {
return go_deeper_in_constant_obfuscation_(depth, random_generator_);
}
@ -289,6 +297,7 @@ class FuzzerContext {
uint32_t chance_of_adding_dead_continue_;
uint32_t chance_of_adding_equation_instruction_;
uint32_t chance_of_adding_global_variable_;
uint32_t chance_of_adding_image_sample_unused_components_;
uint32_t chance_of_adding_load_;
uint32_t chance_of_adding_local_variable_;
uint32_t chance_of_adding_matrix_type_;

View File

@ -0,0 +1,200 @@
// Copyright (c) 2020 André Perez Maselco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/transformation_add_image_sample_unused_components.h"
#include "source/fuzz/transformation_composite_construct.h"
namespace spvtools {
namespace fuzz {
FuzzerPassAddImageSampleUnusedComponents::
FuzzerPassAddImageSampleUnusedComponents(
opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
FuzzerPassAddImageSampleUnusedComponents::
~FuzzerPassAddImageSampleUnusedComponents() = default;
void FuzzerPassAddImageSampleUnusedComponents::Apply() {
// SPIR-V module to help understand the transformation.
//
// OpCapability Shader
// %1 = OpExtInstImport "GLSL.std.450"
// OpMemoryModel Logical GLSL450
// OpEntryPoint Fragment %15 "main" %12 %14
// OpExecutionMode %15 OriginUpperLeft
//
// ; Decorations
// OpDecorate %12 Location 0 ; Input color variable location
// OpDecorate %13 DescriptorSet 0 ; Image coordinate variable
// descriptor set OpDecorate %13 Binding 0 ; Image coordinate
// variable binding OpDecorate %14 Location 0 ; Fragment color
// variable location
//
// ; Types
// %2 = OpTypeVoid
// %3 = OpTypeFunction %2
// %4 = OpTypeFloat 32
// %5 = OpTypeVector %4 2
// %6 = OpTypeVector %4 4
// %7 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
// %8 = OpTypeSampledImage %7
// %9 = OpTypePointer Input %5
// %10 = OpTypePointer UniformConstant %8
// %11 = OpTypePointer Output %6
//
// ; Variables
// %12 = OpVariable %9 Input ; Input image coordinate variable
// %13 = OpVariable %10 UniformConstant ; Image variable
// %14 = OpVariable %11 Output ; Fragment color variable
//
// ; main function
// %15 = OpFunction %2 None %3
// %16 = OpLabel
// %17 = OpLoad %5 %12
// %18 = OpLoad %8 %13
// %19 = OpImageSampleImplicitLod %6 %18 %17
// OpStore %14 %19
// OpReturn
// OpFunctionEnd
GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
// |instruction| %19 = OpImageSampleImplicitLod %6 %18 %17
if (!spvOpcodeIsImageSample(instruction->opcode())) {
return;
}
if (!GetFuzzerContext()->ChoosePercentage(
GetFuzzerContext()
->GetChanceOfAddingImageSampleUnusedComponents())) {
return;
}
// Gets image sample coordinate information.
// |coordinate_instruction| %17 = OpLoad %5 %12
uint32_t coordinate_id = instruction->GetSingleWordInOperand(1);
auto coordinate_instruction =
GetIRContext()->get_def_use_mgr()->GetDef(coordinate_id);
auto coordinate_type = GetIRContext()->get_type_mgr()->GetType(
coordinate_instruction->type_id());
// If the coordinate is a 4-dimensional vector, then no unused components
// may be added.
if (coordinate_type->AsVector() &&
coordinate_type->AsVector()->element_count() == 4) {
return;
}
// If the coordinate is a scalar, then at most 3 unused components may be
// added. If the coordinate is a vector, then the maximum number of unused
// components depends on the vector size.
// For the sample module, the coordinate type instruction is %5 =
// OpTypeVector %4 2, thus |max_unused_component_count| = 4 - 2 = 2.
uint32_t max_unused_component_count =
coordinate_type->AsInteger() || coordinate_type->AsFloat()
? 3
: 4 - coordinate_type->AsVector()->element_count();
// |unused_component_count| may be 1 or 2.
uint32_t unused_component_count =
GetFuzzerContext()->GetRandomUnusedComponentCountForImageSample(
max_unused_component_count);
// Gets a type for the zero-unused components.
uint32_t zero_constant_type_id;
switch (unused_component_count) {
case 1:
// If the coordinate is an integer or float, then the unused components
// type is the same as the coordinate. If the coordinate is a vector,
// then the unused components type is the same as the vector components
// type.
zero_constant_type_id =
coordinate_type->AsInteger() || coordinate_type->AsFloat()
? coordinate_instruction->type_id()
: GetIRContext()->get_type_mgr()->GetId(
coordinate_type->AsVector()->element_type());
break;
case 2:
case 3:
// If the coordinate is an integer or float, then the unused components
// type is the same as the coordinate. If the coordinate is a vector,
// then the unused components type is the same as the coordinate
// components type.
// |zero_constant_type_id| %5 = OpTypeVector %4 2
zero_constant_type_id =
coordinate_type->AsInteger() || coordinate_type->AsFloat()
? FindOrCreateVectorType(coordinate_instruction->type_id(),
unused_component_count)
: FindOrCreateVectorType(
GetIRContext()->get_type_mgr()->GetId(
coordinate_type->AsVector()->element_type()),
unused_component_count);
break;
default:
assert(false && "Should be unreachable.");
zero_constant_type_id = 0;
break;
}
// Gets |coordinate_type| again because the module may have changed due to
// the use of FindOrCreateVectorType above.
coordinate_type = GetIRContext()->get_type_mgr()->GetType(
coordinate_instruction->type_id());
// If the new vector type with unused components does not exist, then create
// it. |coordinate_with_unused_components_type_id| %6 = OpTypeVector %4 4
uint32_t coordinate_with_unused_components_type_id =
coordinate_type->AsInteger() || coordinate_type->AsFloat()
? FindOrCreateVectorType(coordinate_instruction->type_id(),
1 + unused_component_count)
: FindOrCreateVectorType(
GetIRContext()->get_type_mgr()->GetId(
coordinate_type->AsVector()->element_type()),
coordinate_type->AsVector()->element_count() +
unused_component_count);
// Inserts an OpCompositeConstruct instruction which
// represents the coordinate with unused components.
// |coordinate_with_unused_components_id|
// %22 = OpCompositeConstruct %6 %17 %21
uint32_t coordinate_with_unused_components_id =
GetFuzzerContext()->GetFreshId();
ApplyTransformation(TransformationCompositeConstruct(
coordinate_with_unused_components_type_id,
{coordinate_instruction->result_id(),
// FindOrCreateZeroConstant
// %20 = OpConstant %4 0
// %21 = OpConstantComposite %5 %20 %20
FindOrCreateZeroConstant(zero_constant_type_id)},
MakeInstructionDescriptor(GetIRContext(), instruction),
coordinate_with_unused_components_id));
// Tries to add unused components to the image sample coordinate.
// %19 = OpImageSampleImplicitLod %6 %18 %22
ApplyTransformation(TransformationAddImageSampleUnusedComponents(
coordinate_with_unused_components_id,
MakeInstructionDescriptor(GetIRContext(), instruction)));
});
}
} // namespace fuzz
} // namespace spvtools

View File

@ -0,0 +1,41 @@
// Copyright (c) 2020 André Perez Maselco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
#define SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
#include "source/fuzz/fuzzer_pass.h"
namespace spvtools {
namespace fuzz {
// This fuzzer pass searches for image sample instructions in the module and
// randomly applies the transformation to add unused components to the image
// sample coordinate.
class FuzzerPassAddImageSampleUnusedComponents : public FuzzerPass {
public:
FuzzerPassAddImageSampleUnusedComponents(
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations);
~FuzzerPassAddImageSampleUnusedComponents();
void Apply() override;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_

View File

@ -383,6 +383,7 @@ message Transformation {
TransformationAddParameter add_parameter = 52;
TransformationAddCopyMemory add_copy_memory = 53;
TransformationInvertComparisonOperator invert_comparison_operator = 54;
TransformationAddImageSampleUnusedComponents add_image_sample_unused_components = 55;
// Add additional option using the next available number.
}
}
@ -616,6 +617,18 @@ message TransformationAddGlobalVariable {
}
message TransformationAddImageSampleUnusedComponents {
// A transformation that adds unused components to an image sample coordinate.
// An vector id with the original coordinate and the unused components.
uint32 coordinate_with_unused_components_id = 1;
// A descriptor for an image sample instruction.
InstructionDescriptor instruction_descriptor = 2;
}
message TransformationAddLocalVariable {
// Adds a local variable of the given type (which must be a pointer with

View File

@ -29,6 +29,7 @@
#include "source/fuzz/transformation_add_function.h"
#include "source/fuzz/transformation_add_global_undef.h"
#include "source/fuzz/transformation_add_global_variable.h"
#include "source/fuzz/transformation_add_image_sample_unused_components.h"
#include "source/fuzz/transformation_add_local_variable.h"
#include "source/fuzz/transformation_add_no_contraction_decoration.h"
#include "source/fuzz/transformation_add_parameter.h"
@ -112,6 +113,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
case protobufs::Transformation::TransformationCase::kAddGlobalVariable:
return MakeUnique<TransformationAddGlobalVariable>(
message.add_global_variable());
case protobufs::Transformation::TransformationCase::
kAddImageSampleUnusedComponents:
return MakeUnique<TransformationAddImageSampleUnusedComponents>(
message.add_image_sample_unused_components());
case protobufs::Transformation::TransformationCase::kAddLocalVariable:
return MakeUnique<TransformationAddLocalVariable>(
message.add_local_variable());

View File

@ -0,0 +1,117 @@
// Copyright (c) 2020 André Perez Maselco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/fuzz/transformation_add_image_sample_unused_components.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/instruction_descriptor.h"
namespace spvtools {
namespace fuzz {
TransformationAddImageSampleUnusedComponents::
TransformationAddImageSampleUnusedComponents(
const spvtools::fuzz::protobufs::
TransformationAddImageSampleUnusedComponents& message)
: message_(message) {}
TransformationAddImageSampleUnusedComponents::
TransformationAddImageSampleUnusedComponents(
uint32_t coordinate_with_unused_components_id,
const protobufs::InstructionDescriptor& instruction_descriptor) {
message_.set_coordinate_with_unused_components_id(
coordinate_with_unused_components_id);
*message_.mutable_instruction_descriptor() = instruction_descriptor;
}
bool TransformationAddImageSampleUnusedComponents::IsApplicable(
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
auto image_sample_instruction =
FindInstruction(message_.instruction_descriptor(), ir_context);
// The image sample instruction must be defined.
if (image_sample_instruction == nullptr) {
return false;
}
// The instruction must be an image sample instruction.
if (!spvOpcodeIsImageSample(image_sample_instruction->opcode())) {
return false;
}
uint32_t coordinate_id = image_sample_instruction->GetSingleWordInOperand(1);
auto coordinate_instruction =
ir_context->get_def_use_mgr()->GetDef(coordinate_id);
auto coordinate_type =
ir_context->get_type_mgr()->GetType(coordinate_instruction->type_id());
// It must be possible to add unused components.
if (coordinate_type->AsVector() &&
coordinate_type->AsVector()->element_count() == 4) {
return false;
}
auto coordinate_with_unused_components_instruction =
ir_context->get_def_use_mgr()->GetDef(
message_.coordinate_with_unused_components_id());
// The coordinate with unused components instruction must be defined.
if (coordinate_with_unused_components_instruction == nullptr) {
return false;
}
// It must be an OpCompositeConstruct instruction such that it can be checked
// that the original components are present.
if (coordinate_with_unused_components_instruction->opcode() !=
SpvOpCompositeConstruct) {
return false;
}
// The first constituent must be the original coordinate.
if (coordinate_with_unused_components_instruction->GetSingleWordInOperand(
0) != coordinate_id) {
return false;
}
auto coordinate_with_unused_components_type =
ir_context->get_type_mgr()->GetType(
coordinate_with_unused_components_instruction->type_id());
// |coordinate_with_unused_components_type| must be a vector.
if (!coordinate_with_unused_components_type->AsVector()) {
return false;
}
return true;
}
void TransformationAddImageSampleUnusedComponents::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
// Sets the coordinate operand.
auto image_sample_instruction =
FindInstruction(message_.instruction_descriptor(), ir_context);
image_sample_instruction->SetInOperand(
1, {message_.coordinate_with_unused_components_id()});
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
}
protobufs::Transformation
TransformationAddImageSampleUnusedComponents::ToMessage() const {
protobufs::Transformation result;
*result.mutable_add_image_sample_unused_components() = message_;
return result;
}
} // namespace fuzz
} // namespace spvtools

View File

@ -0,0 +1,57 @@
// Copyright (c) 2020 André Perez Maselco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
#define SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
class TransformationAddImageSampleUnusedComponents : public Transformation {
public:
explicit TransformationAddImageSampleUnusedComponents(
const protobufs::TransformationAddImageSampleUnusedComponents& message);
TransformationAddImageSampleUnusedComponents(
uint32_t coordinate_with_unused_components_id,
const protobufs::InstructionDescriptor& instruction_descriptor);
// - |coordinate_with_unused_components_id| must identify a vector such that
// the first components match the components of the image sample coordinate.
// - |message_.instruction_descriptor| must identify an image sample
// instruction
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// Add unused components to an image sample coordinate by replacing the
// coordinate with |coordinate_with_unused_components_id|.
void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
protobufs::Transformation ToMessage() const override;
private:
protobufs::TransformationAddImageSampleUnusedComponents message_;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_

View File

@ -666,6 +666,26 @@ bool spvOpcodeIsLinearAlgebra(SpvOp opcode) {
}
}
bool spvOpcodeIsImageSample(const SpvOp opcode) {
switch (opcode) {
case SpvOpImageSampleImplicitLod:
case SpvOpImageSampleExplicitLod:
case SpvOpImageSampleDrefImplicitLod:
case SpvOpImageSampleDrefExplicitLod:
case SpvOpImageSampleProjImplicitLod:
case SpvOpImageSampleProjExplicitLod:
case SpvOpImageSampleProjDrefImplicitLod:
case SpvOpImageSampleProjDrefExplicitLod:
case SpvOpImageSparseSampleImplicitLod:
case SpvOpImageSparseSampleExplicitLod:
case SpvOpImageSparseSampleDrefImplicitLod:
case SpvOpImageSparseSampleDrefExplicitLod:
return true;
default:
return false;
}
}
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
switch (opcode) {
case SpvOpMemoryBarrier:

View File

@ -137,6 +137,9 @@ bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode);
// Returns true for opcodes that represents linear algebra instructions.
bool spvOpcodeIsLinearAlgebra(SpvOp opcode);
// Returns true for opcodes that represents an image sample instruction.
bool spvOpcodeIsImageSample(SpvOp opcode);
// Returns a vector containing the indices of the memory semantics <id>
// operands for |opcode|.
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);

View File

@ -36,6 +36,7 @@ if (${SPIRV_BUILD_FUZZER})
transformation_add_function_test.cpp
transformation_add_global_undef_test.cpp
transformation_add_global_variable_test.cpp
transformation_add_image_sample_unused_components_test.cpp
transformation_add_local_variable_test.cpp
transformation_add_no_contraction_decoration_test.cpp
transformation_add_parameter_test.cpp

View File

@ -0,0 +1,256 @@
// Copyright (c) 2020 André Perez Maselco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/fuzz/transformation_add_image_sample_unused_components.h"
#include "source/fuzz/instruction_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
TEST(TransformationAddImageSampleUnusedComponentsTest, IsApplicable) {
std::string shader = R"(
OpCapability Shader
OpCapability LiteralSampler
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %18 "main" %17
OpExecutionMode %18 OriginUpperLeft
OpSource ESSL 310
OpName %18 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpTypeFloat 32
%5 = OpTypeVector %4 2
%6 = OpTypeVector %4 3
%7 = OpTypeVector %4 4
%8 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
%9 = OpTypePointer Image %8
%10 = OpTypeSampledImage %8
%11 = OpTypeSampler
%12 = OpConstant %4 1
%13 = OpConstant %4 2
%14 = OpConstant %4 3
%15 = OpConstant %4 4
%16 = OpConstantSampler %11 None 0 Linear
%17 = OpVariable %9 Image
%18 = OpFunction %2 None %3
%19 = OpLabel
%20 = OpLoad %8 %17
%21 = OpSampledImage %10 %20 %16
%22 = OpCompositeConstruct %5 %12 %13
%23 = OpCompositeConstruct %6 %22 %14
%24 = OpCompositeConstruct %7 %23 %15
%25 = OpImageSampleImplicitLod %7 %21 %22
%26 = OpImageSampleExplicitLod %7 %21 %23 Lod %12
%27 = OpImageSampleExplicitLod %7 %21 %24 Lod %12
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_5;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
// Tests applicable image instruction.
auto instruction_descriptor =
MakeInstructionDescriptor(25, SpvOpImageSampleImplicitLod, 0);
auto transformation =
TransformationAddImageSampleUnusedComponents(23, instruction_descriptor);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
instruction_descriptor =
MakeInstructionDescriptor(26, SpvOpImageSampleExplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(24, instruction_descriptor);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
// Tests undefined image instructions.
instruction_descriptor =
MakeInstructionDescriptor(27, SpvOpImageSampleImplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(23, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
instruction_descriptor =
MakeInstructionDescriptor(28, SpvOpImageSampleExplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(23, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
// Tests non-image instructions.
instruction_descriptor = MakeInstructionDescriptor(19, SpvOpLabel, 0);
transformation =
TransformationAddImageSampleUnusedComponents(24, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
instruction_descriptor = MakeInstructionDescriptor(20, SpvOpLoad, 0);
transformation =
TransformationAddImageSampleUnusedComponents(24, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
// Tests coordinate operand being a vec4.
instruction_descriptor =
MakeInstructionDescriptor(27, SpvOpImageSampleExplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(22, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
// Tests undefined coordinate with unused operands.
instruction_descriptor =
MakeInstructionDescriptor(25, SpvOpImageSampleImplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(27, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
// Tests coordinate with unused operands being a non-OpCompositeConstruct
// instruction.
instruction_descriptor =
MakeInstructionDescriptor(25, SpvOpImageSampleImplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(21, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
// Tests the first OpCompositeConstruct constituent not being the original
// coordinate.
instruction_descriptor =
MakeInstructionDescriptor(25, SpvOpImageSampleImplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(22, instruction_descriptor);
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationAddImageSampleUnusedComponentsTest, Apply) {
std::string reference_shader = R"(
OpCapability Shader
OpCapability LiteralSampler
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %18 "main" %17
OpExecutionMode %18 OriginUpperLeft
OpSource ESSL 310
OpName %18 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpTypeFloat 32
%5 = OpTypeVector %4 2
%6 = OpTypeVector %4 3
%7 = OpTypeVector %4 4
%8 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
%9 = OpTypePointer Image %8
%10 = OpTypeSampledImage %8
%11 = OpTypeSampler
%12 = OpConstant %4 1
%13 = OpConstant %4 2
%14 = OpConstant %4 3
%15 = OpConstant %4 4
%16 = OpConstantSampler %11 None 0 Linear
%17 = OpVariable %9 Image
%18 = OpFunction %2 None %3
%19 = OpLabel
%20 = OpLoad %8 %17
%21 = OpSampledImage %10 %20 %16
%22 = OpCompositeConstruct %5 %12 %13
%23 = OpCompositeConstruct %6 %22 %14
%24 = OpCompositeConstruct %7 %23 %15
%25 = OpImageSampleImplicitLod %7 %21 %22
%26 = OpImageSampleExplicitLod %7 %21 %23 Lod %12
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_5;
const auto consumer = nullptr;
const auto context =
BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto instruction_descriptor =
MakeInstructionDescriptor(25, SpvOpImageSampleImplicitLod, 0);
auto transformation =
TransformationAddImageSampleUnusedComponents(23, instruction_descriptor);
transformation.Apply(context.get(), &transformation_context);
instruction_descriptor =
MakeInstructionDescriptor(26, SpvOpImageSampleExplicitLod, 0);
transformation =
TransformationAddImageSampleUnusedComponents(24, instruction_descriptor);
transformation.Apply(context.get(), &transformation_context);
std::string variant_shader = R"(
OpCapability Shader
OpCapability LiteralSampler
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %18 "main" %17
OpExecutionMode %18 OriginUpperLeft
OpSource ESSL 310
OpName %18 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpTypeFloat 32
%5 = OpTypeVector %4 2
%6 = OpTypeVector %4 3
%7 = OpTypeVector %4 4
%8 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
%9 = OpTypePointer Image %8
%10 = OpTypeSampledImage %8
%11 = OpTypeSampler
%12 = OpConstant %4 1
%13 = OpConstant %4 2
%14 = OpConstant %4 3
%15 = OpConstant %4 4
%16 = OpConstantSampler %11 None 0 Linear
%17 = OpVariable %9 Image
%18 = OpFunction %2 None %3
%19 = OpLabel
%20 = OpLoad %8 %17
%21 = OpSampledImage %10 %20 %16
%22 = OpCompositeConstruct %5 %12 %13
%23 = OpCompositeConstruct %6 %22 %14
%24 = OpCompositeConstruct %7 %23 %15
%25 = OpImageSampleImplicitLod %7 %21 %23
%26 = OpImageSampleExplicitLod %7 %21 %24 Lod %12
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools