fuzzer_pass_add_dead_breaks.cpp 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright (c) 2019 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_add_dead_breaks.h"
  15. #include "source/fuzz/transformation_add_dead_break.h"
  16. #include "source/opt/ir_context.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks(
  20. opt::IRContext* ir_context, FactManager* fact_manager,
  21. FuzzerContext* fuzzer_context,
  22. protobufs::TransformationSequence* transformations)
  23. : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
  24. FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default;
  25. void FuzzerPassAddDeadBreaks::Apply() {
  26. // We first collect up lots of possibly-applicable transformations.
  27. std::vector<TransformationAddDeadBreak> candidate_transformations;
  28. // We consider each function separately.
  29. for (auto& function : *GetIRContext()->module()) {
  30. // For a given function, we find all the merge blocks in that function.
  31. std::vector<uint32_t> merge_block_ids;
  32. for (auto& block : function) {
  33. auto maybe_merge_id = block.MergeBlockIdIfAny();
  34. if (maybe_merge_id) {
  35. merge_block_ids.push_back(maybe_merge_id);
  36. }
  37. }
  38. // We rather aggressively consider the possibility of adding a break from
  39. // every block in the function to every merge block. Many of these will be
  40. // inapplicable as they would be illegal. That's OK - we later discard the
  41. // ones that turn out to be no good.
  42. for (auto& block : function) {
  43. for (auto merge_block_id : merge_block_ids) {
  44. // TODO(afd): right now we completely ignore OpPhi instructions at
  45. // merge blocks. This will lead to interesting opportunities being
  46. // missed.
  47. auto candidate_transformation = TransformationAddDeadBreak(
  48. block.id(), merge_block_id,
  49. GetFuzzerContext()->GetRandomGenerator()->RandomBool(), {});
  50. if (candidate_transformation.IsApplicable(GetIRContext(),
  51. *GetFactManager())) {
  52. // Only consider a transformation as a candidate if it is applicable.
  53. candidate_transformations.push_back(
  54. std::move(candidate_transformation));
  55. }
  56. }
  57. }
  58. }
  59. // Go through the candidate transformations that were accumulated,
  60. // probabilistically deciding whether to consider each one further and
  61. // applying the still-applicable ones that are considered further.
  62. //
  63. // We iterate through the candidate transformations in a random order by
  64. // repeatedly removing a random candidate transformation from the sequence
  65. // until no candidate transformations remain. This is done because
  66. // transformations can potentially disable one another, so that iterating
  67. // through them in order would lead to a higher probability of
  68. // transformations appearing early in the sequence being applied compared
  69. // with later transformations.
  70. while (!candidate_transformations.empty()) {
  71. // Choose a random index into the sequence of remaining candidate
  72. // transformations.
  73. auto index = GetFuzzerContext()->GetRandomGenerator()->RandomUint32(
  74. static_cast<uint32_t>(candidate_transformations.size()));
  75. // Remove the transformation at the chosen index from the sequence.
  76. auto transformation = std::move(candidate_transformations[index]);
  77. candidate_transformations.erase(candidate_transformations.begin() + index);
  78. // Probabilistically decide whether to try to apply it vs. ignore it, in the
  79. // case that it is applicable.
  80. if (transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
  81. GetFuzzerContext()->GetRandomGenerator()->RandomPercentage() >
  82. GetFuzzerContext()->GetChanceOfAddingDeadBreak()) {
  83. transformation.Apply(GetIRContext(), GetFactManager());
  84. *GetTransformations()->add_transformation() = transformation.ToMessage();
  85. }
  86. }
  87. }
  88. } // namespace fuzz
  89. } // namespace spvtools