fuzzer_pass_permute_blocks.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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_permute_blocks.h"
  15. #include "source/fuzz/transformation_move_block_down.h"
  16. namespace spvtools {
  17. namespace fuzz {
  18. FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks(
  19. opt::IRContext* ir_context, FactManager* fact_manager,
  20. FuzzerContext* fuzzer_context,
  21. protobufs::TransformationSequence* transformations)
  22. : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
  23. FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default;
  24. void FuzzerPassPermuteBlocks::Apply() {
  25. // For now we do something very simple: we randomly decide whether to move a
  26. // block, and for each block that we do move, we push it down as far as we
  27. // legally can.
  28. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2635): it would be
  29. // nice to randomly sample from the set of legal block permutations and then
  30. // encode the chosen permutation via a series of move-block-down
  31. // transformations. This should be possible but will require some thought.
  32. for (auto& function : *GetIRContext()->module()) {
  33. std::vector<uint32_t> block_ids;
  34. // Collect all block ids for the function before messing with block
  35. // ordering.
  36. for (auto& block : function) {
  37. block_ids.push_back(block.id());
  38. }
  39. // Now consider each block id. We consider block ids in reverse, because
  40. // e.g. in code generated from the following:
  41. //
  42. // if (...) {
  43. // A
  44. // B
  45. // } else {
  46. // C
  47. // }
  48. //
  49. // block A cannot be moved down, but B has freedom to move and that movement
  50. // would provide more freedom for A to move.
  51. for (auto id = block_ids.rbegin(); id != block_ids.rend(); ++id) {
  52. // Randomly decide whether to ignore the block id.
  53. if (!GetFuzzerContext()->ChoosePercentage(
  54. GetFuzzerContext()->GetChanceOfMovingBlockDown())) {
  55. continue;
  56. }
  57. // Keep pushing the block down, until pushing down fails.
  58. // The loop is guaranteed to terminate because a block cannot be pushed
  59. // down indefinitely.
  60. while (true) {
  61. TransformationMoveBlockDown transformation(*id);
  62. if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) {
  63. transformation.Apply(GetIRContext(), GetFactManager());
  64. *GetTransformations()->add_transformation() =
  65. transformation.ToMessage();
  66. } else {
  67. break;
  68. }
  69. }
  70. }
  71. }
  72. }
  73. } // namespace fuzz
  74. } // namespace spvtools