fuzzer_pass_permute_blocks.cpp 2.9 KB

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