| // 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 |