fuzzer_pass_inline_functions.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright (c) 2020 André Perez Maselco
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/fuzzer_pass_inline_functions.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/instruction_descriptor.h"
  17. #include "source/fuzz/transformation_inline_function.h"
  18. #include "source/fuzz/transformation_split_block.h"
  19. namespace spvtools {
  20. namespace fuzz {
  21. FuzzerPassInlineFunctions::FuzzerPassInlineFunctions(
  22. opt::IRContext* ir_context, TransformationContext* transformation_context,
  23. FuzzerContext* fuzzer_context,
  24. protobufs::TransformationSequence* transformations,
  25. bool ignore_inapplicable_transformations)
  26. : FuzzerPass(ir_context, transformation_context, fuzzer_context,
  27. transformations, ignore_inapplicable_transformations) {}
  28. void FuzzerPassInlineFunctions::Apply() {
  29. // |function_call_instructions| are the instructions that will be inlined.
  30. // First, they will be collected and then do the inlining in another loop.
  31. // This avoids changing the module while it is being inspected.
  32. std::vector<opt::Instruction*> function_call_instructions;
  33. for (auto& function : *GetIRContext()->module()) {
  34. for (auto& block : function) {
  35. for (auto& instruction : block) {
  36. if (!GetFuzzerContext()->ChoosePercentage(
  37. GetFuzzerContext()->GetChanceOfInliningFunction())) {
  38. continue;
  39. }
  40. // |instruction| must be suitable for inlining.
  41. if (!TransformationInlineFunction::IsSuitableForInlining(
  42. GetIRContext(), &instruction)) {
  43. continue;
  44. }
  45. function_call_instructions.push_back(&instruction);
  46. }
  47. }
  48. }
  49. // Once the function calls have been collected, it's time to actually create
  50. // and apply the inlining transformations.
  51. for (auto& function_call_instruction : function_call_instructions) {
  52. // If |function_call_instruction| is not the penultimate instruction in its
  53. // block or its block termination instruction is not OpBranch, then try to
  54. // split |function_call_block| such that the conditions are met.
  55. auto* function_call_block =
  56. GetIRContext()->get_instr_block(function_call_instruction);
  57. if ((function_call_instruction != &*--function_call_block->tail() ||
  58. function_call_block->terminator()->opcode() != spv::Op::OpBranch) &&
  59. !MaybeApplyTransformation(TransformationSplitBlock(
  60. MakeInstructionDescriptor(GetIRContext(),
  61. function_call_instruction->NextNode()),
  62. GetFuzzerContext()->GetFreshId()))) {
  63. continue;
  64. }
  65. auto* called_function = fuzzerutil::FindFunction(
  66. GetIRContext(), function_call_instruction->GetSingleWordInOperand(0));
  67. // Mapping the called function instructions.
  68. std::map<uint32_t, uint32_t> result_id_map;
  69. for (auto& called_function_block : *called_function) {
  70. // The called function entry block label will not be inlined.
  71. if (&called_function_block != &*called_function->entry()) {
  72. result_id_map[called_function_block.GetLabelInst()->result_id()] =
  73. GetFuzzerContext()->GetFreshId();
  74. }
  75. for (auto& instruction_to_inline : called_function_block) {
  76. // The instructions are mapped to fresh ids.
  77. if (instruction_to_inline.HasResultId()) {
  78. result_id_map[instruction_to_inline.result_id()] =
  79. GetFuzzerContext()->GetFreshId();
  80. }
  81. }
  82. }
  83. // Applies the inline function transformation.
  84. ApplyTransformation(TransformationInlineFunction(
  85. function_call_instruction->result_id(), result_id_map));
  86. }
  87. }
  88. } // namespace fuzz
  89. } // namespace spvtools