blob: 19661d103bbf5dfb4f72547c12799ffa8cf51002 [file] [log] [blame]
// 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,
bool ignore_inapplicable_transformations)
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations, ignore_inapplicable_transformations) {}
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, true)},
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