Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit f5f6185

Browse files
committed
[PM/Unswitch] Teach SimpleLoopUnswitch to do non-trivial unswitching,
making it no longer even remotely simple. The pass will now be more of a "full loop unswitching" pass rather than anything substantively simpler than any other approach. I plan to rename it accordingly once the dust settles. The key ideas of the new loop unswitcher are carried over for non-trivial unswitching: 1) Fully unswitch a branch or switch instruction from inside of a loop to outside of it. 2) Update the CFG and IR. This avoids needing to "remember" the unswitched branches as well as avoiding excessively cloning and reliance on complex parts of simplify-cfg to cleanup the cfg. 3) Update the analyses (where we can) rather than just blowing them away or relying on something else updating them. Sadly, #3 is somewhat compromised here as the dominator tree updates were too complex for me to want to reason about. I will need to make another attempt to do this now that we have a nice dynamic update API for dominators. However, we do adhere to #3 w.r.t. LoopInfo. This approach also adds an important principls specific to non-trivial unswitching: not *all* of the loop will be duplicated when unswitching. This fact allows us to compute the cost in terms of how much *duplicate* code is inserted rather than just on raw size. Unswitching conditions which essentialy partition loops will work regardless of the total loop size. Some remaining issues that I will be addressing in subsequent commits: - Handling unstructured control flow. - Unswitching 'switch' cases instead of just branches. - Moving to the dynamic update API for dominators. Some high-level, interesting limitationsV that folks might want to push on as follow-ups but that I don't have any immediate plans around: - We could be much more clever about not cloning things that will be deleted. In fact, we should be able to delete *nothing* and do a minimal number of clones. - There are many more interesting selection criteria for which branch to unswitch that we might want to look at. One that I'm interested in particularly are a set of conditions which all exit the loop and which can be merged into a single unswitched test of them. Differential revision: https://reviews.llvm.org/D34200 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@318549 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 9bde5fb commit f5f6185

File tree

9 files changed

+4372
-100
lines changed

9 files changed

+4372
-100
lines changed

include/llvm/Analysis/LoopInfo.h

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,11 @@ template <class BlockT, class LoopT> class LoopBase {
146146
bool empty() const { return getSubLoops().empty(); }
147147

148148
/// Get a list of the basic blocks which make up this loop.
149-
const std::vector<BlockT *> &getBlocks() const {
149+
ArrayRef<BlockT *> getBlocks() const {
150150
assert(!isInvalid() && "Loop not in a valid state!");
151151
return Blocks;
152152
}
153-
typedef typename std::vector<BlockT *>::const_iterator block_iterator;
153+
typedef typename ArrayRef<BlockT *>::const_iterator block_iterator;
154154
block_iterator block_begin() const { return getBlocks().begin(); }
155155
block_iterator block_end() const { return getBlocks().end(); }
156156
inline iterator_range<block_iterator> blocks() const {
@@ -165,6 +165,19 @@ template <class BlockT, class LoopT> class LoopBase {
165165
return Blocks.size();
166166
}
167167

168+
/// Return a direct, mutable handle to the blocks vector so that we can
169+
/// mutate it efficiently with techniques like `std::remove`.
170+
std::vector<BlockT *> &getBlocksVector() {
171+
assert(!isInvalid() && "Loop not in a valid state!");
172+
return Blocks;
173+
}
174+
/// Return a direct, mutable handle to the blocks set so that we can
175+
/// mutate it efficiently.
176+
SmallPtrSetImpl<const BlockT *> &getBlocksSet() {
177+
assert(!isInvalid() && "Loop not in a valid state!");
178+
return DenseBlockSet;
179+
}
180+
168181
/// Return true if this loop is no longer valid. The only valid use of this
169182
/// helper is "assert(L.isInvalid())" or equivalent, since IsInvalid is set to
170183
/// true by the destructor. In other words, if this accessor returns true,
@@ -314,6 +327,12 @@ template <class BlockT, class LoopT> class LoopBase {
314327
return Child;
315328
}
316329

330+
/// This removes the specified child from being a subloop of this loop. The
331+
/// loop is not deleted, as it will presumably be inserted into another loop.
332+
LoopT *removeChildLoop(LoopT *Child) {
333+
return removeChildLoop(llvm::find(*this, Child));
334+
}
335+
317336
/// This adds a basic block directly to the basic block list.
318337
/// This should only be used by transformations that create new loops. Other
319338
/// transformations should use addBasicBlockToLoop.
@@ -744,9 +763,16 @@ template <class BlockT, class LoopT> class LoopInfoBase {
744763

745764
void verify(const DominatorTreeBase<BlockT, false> &DomTree) const;
746765

747-
protected:
748-
// Calls the destructor for \p L but keeps the memory for \p L around so that
749-
// the pointer value does not get re-used.
766+
/// Destroy a loop that has been removed from the `LoopInfo` nest.
767+
///
768+
/// This runs the destructor of the loop object making it invalid to
769+
/// reference afterward. The memory is retained so that the *pointer* to the
770+
/// loop remains valid.
771+
///
772+
/// The caller is responsible for removing this loop from the loop nest and
773+
/// otherwise disconnecting it from the broader `LoopInfo` data structures.
774+
/// Callers that don't naturally handle this themselves should probably call
775+
/// `erase' instead.
750776
void destroy(LoopT *L) {
751777
L->~LoopT();
752778

include/llvm/Analysis/LoopInfoImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ static void discoverAndMapSubloop(LoopT *L, ArrayRef<BlockT *> Backedges,
400400
// Discover a subloop of this loop.
401401
Subloop->setParentLoop(L);
402402
++NumSubloops;
403-
NumBlocks += Subloop->getBlocks().capacity();
403+
NumBlocks += Subloop->getBlocksVector().capacity();
404404
PredBB = Subloop->getHeader();
405405
// Continue traversal along predecessors that are not loop-back edges from
406406
// within this subloop tree itself. Note that a predecessor may directly

include/llvm/Transforms/Scalar/LoopPassManager.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,19 @@ class LPMUpdater {
217217
// shouldn't impact anything.
218218
}
219219

220+
/// Restart the current loop.
221+
///
222+
/// Loop passes should call this method to indicate the current loop has been
223+
/// sufficiently changed that it should be re-visited from the begining of
224+
/// the loop pass pipeline rather than continuing.
225+
void revisitCurrentLoop() {
226+
// Tell the currently in-flight pipeline to stop running.
227+
SkipCurrentLoop = true;
228+
229+
// And insert ourselves back into the worklist.
230+
Worklist.insert(CurrentL);
231+
}
232+
220233
private:
221234
template <typename LoopPassT> friend class llvm::FunctionToLoopPassAdaptor;
222235

include/llvm/Transforms/Scalar/SimpleLoopUnswitch.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ namespace llvm {
3636
/// of the loop, to make the unswitching opportunity obvious.
3737
///
3838
class SimpleLoopUnswitchPass : public PassInfoMixin<SimpleLoopUnswitchPass> {
39+
bool NonTrivial;
40+
3941
public:
40-
SimpleLoopUnswitchPass() = default;
42+
SimpleLoopUnswitchPass(bool NonTrivial = false) : NonTrivial(NonTrivial) {}
4143

4244
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
4345
LoopStandardAnalysisResults &AR, LPMUpdater &U);
@@ -46,7 +48,7 @@ class SimpleLoopUnswitchPass : public PassInfoMixin<SimpleLoopUnswitchPass> {
4648
/// Create the legacy pass object for the simple loop unswitcher.
4749
///
4850
/// See the documentaion for `SimpleLoopUnswitchPass` for details.
49-
Pass *createSimpleLoopUnswitchLegacyPass();
51+
Pass *createSimpleLoopUnswitchLegacyPass(bool NonTrivial = false);
5052

5153
} // end namespace llvm
5254

lib/Analysis/LoopPass.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ class PrintLoopPassWrapper : public LoopPass {
4646
}
4747

4848
bool runOnLoop(Loop *L, LPPassManager &) override {
49-
auto BBI = find_if(L->blocks().begin(), L->blocks().end(),
50-
[](BasicBlock *BB) { return BB; });
49+
auto BBI = llvm::find_if(L->blocks(), [](BasicBlock *BB) { return BB; });
5150
if (BBI != L->blocks().end() &&
5251
isFunctionInPrintList((*BBI)->getParent()->getName())) {
5352
printLoop(*L, OS, Banner);

0 commit comments

Comments
 (0)