MergeBlocks.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Bytecode/PassManager.h>
  7. namespace JS::Bytecode::Passes {
  8. void MergeBlocks::perform(PassPipelineExecutable& executable)
  9. {
  10. started();
  11. VERIFY(executable.cfg.has_value());
  12. VERIFY(executable.inverted_cfg.has_value());
  13. auto cfg = executable.cfg.release_value();
  14. auto inverted_cfg = executable.inverted_cfg.release_value();
  15. // Figure out which blocks can be merged
  16. HashTable<BasicBlock const*> blocks_to_merge;
  17. HashMap<BasicBlock const*, BasicBlock const*> blocks_to_replace;
  18. Vector<BasicBlock const*> blocks_to_remove;
  19. Vector<size_t> boundaries;
  20. for (auto& entry : cfg) {
  21. if (entry.value.size() != 1)
  22. continue;
  23. if (executable.exported_blocks->contains(*entry.value.begin()))
  24. continue;
  25. {
  26. InstructionStreamIterator it { entry.key->instruction_stream() };
  27. auto& first_instruction = *it;
  28. if (first_instruction.is_terminator()) {
  29. if (first_instruction.type() == Instruction::Type::Jump) {
  30. auto replacing_block = &static_cast<Op::Jump const&>(first_instruction).true_target()->block();
  31. if (replacing_block != entry.key)
  32. blocks_to_replace.set(entry.key, replacing_block);
  33. continue;
  34. }
  35. }
  36. }
  37. if (auto cfg_entry = inverted_cfg.get(*entry.value.begin()); cfg_entry.has_value()) {
  38. auto& predecssor_entry = *cfg_entry;
  39. if (predecssor_entry.size() != 1)
  40. continue;
  41. }
  42. // The two blocks are safe to merge.
  43. blocks_to_merge.set(entry.key);
  44. }
  45. for (auto& entry : blocks_to_replace) {
  46. auto replacement = entry.value;
  47. for (;;) {
  48. auto lookup = blocks_to_replace.get(replacement);
  49. if (!lookup.has_value())
  50. break;
  51. if (replacement == *lookup)
  52. break;
  53. replacement = *lookup;
  54. }
  55. entry.value = replacement;
  56. }
  57. auto replace_blocks = [&](auto& blocks, auto& replacement) {
  58. Optional<size_t> first_successor_position;
  59. for (auto& entry : blocks) {
  60. blocks_to_remove.append(entry);
  61. auto it = executable.executable.basic_blocks.find_if([entry](auto& block) { return entry == block; });
  62. VERIFY(!it.is_end());
  63. if (!first_successor_position.has_value())
  64. first_successor_position = it.index();
  65. }
  66. for (auto& block : executable.executable.basic_blocks) {
  67. InstructionStreamIterator it { block.instruction_stream() };
  68. while (!it.at_end()) {
  69. auto& instruction = *it;
  70. ++it;
  71. for (auto& entry : blocks)
  72. const_cast<Instruction&>(instruction).replace_references(*entry, replacement);
  73. }
  74. }
  75. return first_successor_position;
  76. };
  77. for (auto& entry : blocks_to_replace) {
  78. AK::Array candidates { entry.key };
  79. (void)replace_blocks(candidates, *entry.value);
  80. }
  81. while (!blocks_to_merge.is_empty()) {
  82. auto it = blocks_to_merge.begin();
  83. auto current_block = *it;
  84. blocks_to_merge.remove(it);
  85. Vector<BasicBlock const*> successors { current_block };
  86. for (;;) {
  87. auto last = successors.last();
  88. auto entry = cfg.get(last);
  89. if (!entry.has_value())
  90. break;
  91. auto& successor = *entry->begin();
  92. successors.append(successor);
  93. auto it = blocks_to_merge.find(successor);
  94. if (it == blocks_to_merge.end())
  95. break;
  96. blocks_to_merge.remove(it);
  97. }
  98. auto blocks_to_merge_copy = blocks_to_merge;
  99. for (auto& last : blocks_to_merge) {
  100. auto entry = cfg.get(last);
  101. if (!entry.has_value())
  102. continue;
  103. auto successor = *entry->begin();
  104. if (auto it = successors.find(successor); !it.is_end()) {
  105. successors.insert(it.index(), last);
  106. blocks_to_merge_copy.remove(last);
  107. }
  108. }
  109. blocks_to_merge = move(blocks_to_merge_copy);
  110. size_t size = 0;
  111. StringBuilder builder;
  112. builder.append("merge");
  113. for (auto& entry : successors) {
  114. size += entry->size();
  115. builder.append('.');
  116. builder.append(entry->name());
  117. }
  118. auto new_block = BasicBlock::create(builder.build(), size);
  119. auto& block = *new_block;
  120. size_t last_successor_index = successors.size() - 1;
  121. for (size_t i = 0; i < successors.size(); ++i) {
  122. auto& entry = successors[i];
  123. InstructionStreamIterator it { entry->instruction_stream() };
  124. size_t copy_end = 0;
  125. while (!it.at_end()) {
  126. auto& instruction = *it;
  127. ++it;
  128. if (instruction.is_terminator() && last_successor_index != i)
  129. break;
  130. copy_end = it.offset();
  131. }
  132. __builtin_memcpy(block.next_slot(), entry->instruction_stream().data(), copy_end);
  133. block.grow(copy_end);
  134. }
  135. auto first_successor_position = replace_blocks(successors, *new_block);
  136. VERIFY(first_successor_position.has_value());
  137. executable.executable.basic_blocks.insert(*first_successor_position, move(new_block));
  138. }
  139. executable.executable.basic_blocks.remove_all_matching([&blocks_to_remove](auto& candidate) { return blocks_to_remove.contains_slow(candidate.ptr()); });
  140. finished();
  141. }
  142. }