transformation_merge_blocks.cpp 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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/transformation_merge_blocks.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/opt/block_merge_util.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. TransformationMergeBlocks::TransformationMergeBlocks(
  20. protobufs::TransformationMergeBlocks message)
  21. : message_(std::move(message)) {}
  22. TransformationMergeBlocks::TransformationMergeBlocks(uint32_t block_id) {
  23. message_.set_block_id(block_id);
  24. }
  25. bool TransformationMergeBlocks::IsApplicable(
  26. opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
  27. auto second_block =
  28. fuzzerutil::MaybeFindBlock(ir_context, message_.block_id());
  29. // The given block must exist.
  30. if (!second_block) {
  31. return false;
  32. }
  33. // The block must have just one predecessor.
  34. auto predecessors = ir_context->cfg()->preds(second_block->id());
  35. if (predecessors.size() != 1) {
  36. return false;
  37. }
  38. auto first_block = ir_context->cfg()->block(predecessors.at(0));
  39. if (!ir_context->IsReachable(*first_block)) {
  40. return false;
  41. }
  42. return opt::blockmergeutil::CanMergeWithSuccessor(ir_context, first_block);
  43. }
  44. void TransformationMergeBlocks::Apply(opt::IRContext* ir_context,
  45. TransformationContext* /*unused*/) const {
  46. auto second_block =
  47. fuzzerutil::MaybeFindBlock(ir_context, message_.block_id());
  48. auto first_block = ir_context->cfg()->block(
  49. ir_context->cfg()->preds(second_block->id()).at(0));
  50. auto function = first_block->GetParent();
  51. // We need an iterator pointing to the predecessor, hence the loop.
  52. for (auto bi = function->begin(); bi != function->end(); ++bi) {
  53. if (bi->id() == first_block->id()) {
  54. assert(opt::blockmergeutil::CanMergeWithSuccessor(ir_context, &*bi) &&
  55. "Because 'Apply' should only be invoked if 'IsApplicable' holds, "
  56. "it must be possible to merge |bi| with its successor.");
  57. opt::blockmergeutil::MergeWithSuccessor(ir_context, function, bi);
  58. // Invalidate all analyses, since we have changed the module
  59. // significantly.
  60. ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
  61. return;
  62. }
  63. }
  64. assert(false &&
  65. "Control should not reach here - we should always find the desired "
  66. "block");
  67. }
  68. protobufs::Transformation TransformationMergeBlocks::ToMessage() const {
  69. protobufs::Transformation result;
  70. *result.mutable_merge_blocks() = message_;
  71. return result;
  72. }
  73. std::unordered_set<uint32_t> TransformationMergeBlocks::GetFreshIds() const {
  74. return std::unordered_set<uint32_t>();
  75. }
  76. } // namespace fuzz
  77. } // namespace spvtools