|
20 | 20 | #include "SwitchEnumBuilder.h"
|
21 | 21 | #include "swift/AST/DiagnosticsSIL.h"
|
22 | 22 | #include "swift/Basic/ProfileCounter.h"
|
| 23 | +#include "swift/SIL/BasicBlockUtils.h" |
23 | 24 | #include "swift/SIL/SILArgument.h"
|
24 | 25 | #include "llvm/Support/SaveAndRestore.h"
|
25 | 26 |
|
@@ -97,6 +98,76 @@ void SILGenFunction::eraseBasicBlock(SILBasicBlock *block) {
|
97 | 98 | block->eraseFromParent();
|
98 | 99 | }
|
99 | 100 |
|
| 101 | +// Merge blocks during a single traversal of the block list. Only unconditional |
| 102 | +// branch edges are visited. Consequently, this takes only as much time as a |
| 103 | +// linked list traversal and requires no additional storage. |
| 104 | +// |
| 105 | +// For each block, check if it can be merged with its successor. Place the |
| 106 | +// merged block at the successor position in the block list. |
| 107 | +// |
| 108 | +// Typically, the successor occurs later in the list. This is most efficient |
| 109 | +// because merging moves instructions from the successor to the |
| 110 | +// predecessor. This way, instructions will only be moved once. Furthermore, the |
| 111 | +// merged block will be visited again to determine if it can be merged with it's |
| 112 | +// successor, and so on, so no edges are skipped. |
| 113 | +// |
| 114 | +// In rare cases, the predessor is merged with its earlier successor, which has |
| 115 | +// already been visited. If the successor can also be merged, then it has |
| 116 | +// already happened, and there is no need to revisit the merged block. |
| 117 | +void SILGenFunction::mergeCleanupBlocks() { |
| 118 | + for (auto bbPos = F.begin(), bbEnd = F.end(), nextPos = bbPos; bbPos != bbEnd; |
| 119 | + bbPos = nextPos) { |
| 120 | + // A forward iterator refering to the next unprocessed block in the block |
| 121 | + // list. If blocks are merged and moved, then this will be updated. |
| 122 | + nextPos = std::next(bbPos); |
| 123 | + |
| 124 | + // Consider the current block as the predecessor. |
| 125 | + auto *predBB = &*bbPos; |
| 126 | + auto *BI = dyn_cast<BranchInst>(predBB->getTerminator()); |
| 127 | + if (!BI) |
| 128 | + continue; |
| 129 | + |
| 130 | + // predBB has an unconditional branch to succBB. If succBB has no other |
| 131 | + // predecessors, then merge the blocks. |
| 132 | + auto *succBB = BI->getDestBB(); |
| 133 | + if (!succBB->getSinglePredecessorBlock()) |
| 134 | + continue; |
| 135 | + |
| 136 | + // Before merging, establish iterators that won't be invalidated by erasing |
| 137 | + // succBB. Use a reverse iterator to remember the position before a block. |
| 138 | + // |
| 139 | + // Remember the block before the current successor as a position for placing |
| 140 | + // the merged block. |
| 141 | + auto beforeSucc = std::next(SILFunction::reverse_iterator(succBB)); |
| 142 | + |
| 143 | + // Remember the position before the current predecessor to avoid skipping |
| 144 | + // blocks or revisiting blocks unnecessarilly. |
| 145 | + auto beforePred = std::next(SILFunction::reverse_iterator(predBB)); |
| 146 | + // Since succBB will be erased, move before it. |
| 147 | + if (beforePred == SILFunction::reverse_iterator(succBB)) |
| 148 | + ++beforePred; |
| 149 | + |
| 150 | + // Merge `predBB` with `succBB`. This erases `succBB`. |
| 151 | + mergeBasicBlockWithSingleSuccessor(predBB, succBB); |
| 152 | + |
| 153 | + // If predBB is first in the list, then it must be the entry block which |
| 154 | + // cannot be moved. |
| 155 | + if (beforePred != F.rend()) { |
| 156 | + // Move the merged block into the successor position. (If the blocks are |
| 157 | + // not already adjacent, then the first is typically the trampoline.) |
| 158 | + assert(beforeSucc != F.rend() |
| 159 | + && "entry block cannot have a predecessor."); |
| 160 | + predBB->moveAfter(&*beforeSucc); |
| 161 | + } |
| 162 | + // If after moving predBB there are no more blocks to process, then break. |
| 163 | + if (beforePred == F.rbegin()) |
| 164 | + break; |
| 165 | + |
| 166 | + // Update the loop iterator to the next unprocessed block. |
| 167 | + nextPos = SILFunction::iterator(&*std::prev(beforePred)); |
| 168 | + } |
| 169 | +} |
| 170 | + |
100 | 171 | //===----------------------------------------------------------------------===//
|
101 | 172 | // SILGenFunction emitStmt implementation
|
102 | 173 | //===----------------------------------------------------------------------===//
|
|
0 commit comments