// Copyright (c) 2019 Google LLC // // 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_outline_functions.h" #include #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/transformation_outline_function.h" namespace spvtools { namespace fuzz { FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} FuzzerPassOutlineFunctions::~FuzzerPassOutlineFunctions() = default; void FuzzerPassOutlineFunctions::Apply() { std::vector original_functions; for (auto& function : *GetIRContext()->module()) { original_functions.push_back(&function); } for (auto& function : original_functions) { if (!GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->GetChanceOfOutliningFunction())) { continue; } std::vector blocks; for (auto& block : *function) { blocks.push_back(&block); } auto entry_block = blocks[GetFuzzerContext()->RandomIndex(blocks)]; auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(function); auto postdominator_analysis = GetIRContext()->GetPostDominatorAnalysis(function); std::vector candidate_exit_blocks; for (auto postdominates_entry_block = entry_block; postdominates_entry_block != nullptr; postdominates_entry_block = postdominator_analysis->ImmediateDominator( postdominates_entry_block)) { if (dominator_analysis->Dominates(entry_block, postdominates_entry_block)) { candidate_exit_blocks.push_back(postdominates_entry_block); } } if (candidate_exit_blocks.empty()) { continue; } auto exit_block = candidate_exit_blocks[GetFuzzerContext()->RandomIndex( candidate_exit_blocks)]; auto region_blocks = TransformationOutlineFunction::GetRegionBlocks( GetIRContext(), entry_block, exit_block); std::map input_id_to_fresh_id; for (auto id : TransformationOutlineFunction::GetRegionInputIds( GetIRContext(), region_blocks, exit_block)) { input_id_to_fresh_id[id] = GetFuzzerContext()->GetFreshId(); } std::map output_id_to_fresh_id; for (auto id : TransformationOutlineFunction::GetRegionOutputIds( GetIRContext(), region_blocks, exit_block)) { output_id_to_fresh_id[id] = GetFuzzerContext()->GetFreshId(); } TransformationOutlineFunction transformation( entry_block->id(), exit_block->id(), /*new_function_struct_return_type_id*/ GetFuzzerContext()->GetFreshId(), /*new_function_type_id*/ GetFuzzerContext()->GetFreshId(), /*new_function_id*/ GetFuzzerContext()->GetFreshId(), /*new_function_region_entry_block*/ GetFuzzerContext()->GetFreshId(), /*new_caller_result_id*/ GetFuzzerContext()->GetFreshId(), /*new_callee_result_id*/ GetFuzzerContext()->GetFreshId(), /*input_id_to_fresh_id*/ std::move(input_id_to_fresh_id), /*output_id_to_fresh_id*/ std::move(output_id_to_fresh_id)); if (transformation.IsApplicable(GetIRContext(), *GetTransformationContext())) { transformation.Apply(GetIRContext(), GetTransformationContext()); *GetTransformations()->add_transformation() = transformation.ToMessage(); } } } } // namespace fuzz } // namespace spvtools