fuzzer_pass_duplicate_regions_with_selections.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Copyright (c) 2020 Google LLC
  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_duplicate_regions_with_selections.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/transformation_duplicate_region_with_selection.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. FuzzerPassDuplicateRegionsWithSelections::
  20. FuzzerPassDuplicateRegionsWithSelections(
  21. opt::IRContext* ir_context,
  22. 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 FuzzerPassDuplicateRegionsWithSelections::Apply() {
  29. // Iterate over all of the functions in the module.
  30. for (auto& function : *GetIRContext()->module()) {
  31. // Randomly decide whether to apply the transformation.
  32. if (!GetFuzzerContext()->ChoosePercentage(
  33. GetFuzzerContext()->GetChanceOfDuplicatingRegionWithSelection())) {
  34. continue;
  35. }
  36. std::vector<opt::BasicBlock*> candidate_entry_blocks;
  37. for (auto& block : function) {
  38. // We don't consider the first block to be the entry block, since it
  39. // could contain OpVariable instructions that would require additional
  40. // operations to be reassigned.
  41. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3778):
  42. // Consider extending this fuzzer pass to allow the first block to be
  43. // used in duplication.
  44. if (&block == &*function.begin()) {
  45. continue;
  46. }
  47. candidate_entry_blocks.push_back(&block);
  48. }
  49. if (candidate_entry_blocks.empty()) {
  50. continue;
  51. }
  52. // Randomly choose the entry block.
  53. auto entry_block = candidate_entry_blocks[GetFuzzerContext()->RandomIndex(
  54. candidate_entry_blocks)];
  55. auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(&function);
  56. auto postdominator_analysis =
  57. GetIRContext()->GetPostDominatorAnalysis(&function);
  58. std::vector<opt::BasicBlock*> candidate_exit_blocks;
  59. for (auto postdominates_entry_block = entry_block;
  60. postdominates_entry_block != nullptr;
  61. postdominates_entry_block = postdominator_analysis->ImmediateDominator(
  62. postdominates_entry_block)) {
  63. // The candidate exit block must be dominated by the entry block and the
  64. // entry block must be post-dominated by the candidate exit block. Ignore
  65. // the block if it heads a selection construct or a loop construct.
  66. if (dominator_analysis->Dominates(entry_block,
  67. postdominates_entry_block) &&
  68. !postdominates_entry_block->GetMergeInst()) {
  69. candidate_exit_blocks.push_back(postdominates_entry_block);
  70. }
  71. }
  72. if (candidate_exit_blocks.empty()) {
  73. continue;
  74. }
  75. // Randomly choose the exit block.
  76. auto exit_block = candidate_exit_blocks[GetFuzzerContext()->RandomIndex(
  77. candidate_exit_blocks)];
  78. auto region_blocks =
  79. TransformationDuplicateRegionWithSelection::GetRegionBlocks(
  80. GetIRContext(), entry_block, exit_block);
  81. // Construct |original_label_to_duplicate_label| by iterating over all
  82. // blocks in the region. Construct |original_id_to_duplicate_id| and
  83. // |original_id_to_phi_id| by iterating over all instructions in each block.
  84. std::map<uint32_t, uint32_t> original_label_to_duplicate_label;
  85. std::map<uint32_t, uint32_t> original_id_to_duplicate_id;
  86. std::map<uint32_t, uint32_t> original_id_to_phi_id;
  87. for (auto& block : region_blocks) {
  88. original_label_to_duplicate_label[block->id()] =
  89. GetFuzzerContext()->GetFreshId();
  90. for (auto& instr : *block) {
  91. if (instr.result_id()) {
  92. original_id_to_duplicate_id[instr.result_id()] =
  93. GetFuzzerContext()->GetFreshId();
  94. auto final_instruction = &*exit_block->tail();
  95. // &*exit_block->tail() is the final instruction of the region.
  96. // The instruction is available at the end of the region if and only
  97. // if it is available before this final instruction or it is the final
  98. // instruction.
  99. if ((&instr == final_instruction ||
  100. fuzzerutil::IdIsAvailableBeforeInstruction(
  101. GetIRContext(), final_instruction, instr.result_id()))) {
  102. original_id_to_phi_id[instr.result_id()] =
  103. GetFuzzerContext()->GetFreshId();
  104. }
  105. }
  106. }
  107. }
  108. // Randomly decide between value "true" or "false" for a bool constant.
  109. // Make sure the transformation has access to a bool constant to be used
  110. // while creating conditional construct.
  111. auto condition_id =
  112. FindOrCreateBoolConstant(GetFuzzerContext()->ChooseEven(), true);
  113. TransformationDuplicateRegionWithSelection transformation =
  114. TransformationDuplicateRegionWithSelection(
  115. GetFuzzerContext()->GetFreshId(), condition_id,
  116. GetFuzzerContext()->GetFreshId(), entry_block->id(),
  117. exit_block->id(), original_label_to_duplicate_label,
  118. original_id_to_duplicate_id, original_id_to_phi_id);
  119. MaybeApplyTransformation(transformation);
  120. }
  121. }
  122. } // namespace fuzz
  123. } // namespace spvtools