mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 19:50:05 +00:00
spirv-fuzz: Add image sample unused components transformation (#3439)
Fixes #3375.
This commit is contained in:
parent
7afbc0c8be
commit
daa3b47ed4
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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_ =
|
||||
|
@ -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_;
|
||||
|
200
source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp
Normal file
200
source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp
Normal 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
|
41
source/fuzz/fuzzer_pass_add_image_sample_unused_components.h
Normal file
41
source/fuzz/fuzzer_pass_add_image_sample_unused_components.h
Normal 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_
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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
|
@ -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_
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user