|
|
@ -25,6 +25,8 @@
|
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
|
|
#include "llvm/Analysis/LoopIterator.h"
|
|
|
|
#include "llvm/Analysis/LoopIterator.h"
|
|
|
|
#include "llvm/Analysis/LoopPass.h"
|
|
|
|
#include "llvm/Analysis/LoopPass.h"
|
|
|
|
|
|
|
|
#include "llvm/Analysis/MemorySSA.h"
|
|
|
|
|
|
|
|
#include "llvm/Analysis/MemorySSAUpdater.h"
|
|
|
|
#include "llvm/Analysis/Utils/Local.h"
|
|
|
|
#include "llvm/Analysis/Utils/Local.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/Constant.h"
|
|
|
|
#include "llvm/IR/Constant.h"
|
|
|
@ -349,7 +351,8 @@ static void hoistLoopToNewParent(Loop &L, BasicBlock &Preheader,
|
|
|
|
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
|
|
|
|
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
|
|
|
|
/// invalidated by this.
|
|
|
|
/// invalidated by this.
|
|
|
|
static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
LoopInfo &LI, ScalarEvolution *SE) {
|
|
|
|
LoopInfo &LI, ScalarEvolution *SE,
|
|
|
|
|
|
|
|
MemorySSAUpdater *MSSAU) {
|
|
|
|
assert(BI.isConditional() && "Can only unswitch a conditional branch!");
|
|
|
|
assert(BI.isConditional() && "Can only unswitch a conditional branch!");
|
|
|
|
LLVM_DEBUG(dbgs() << " Trying to unswitch branch: " << BI << "\n");
|
|
|
|
LLVM_DEBUG(dbgs() << " Trying to unswitch branch: " << BI << "\n");
|
|
|
|
|
|
|
|
|
|
|
@ -423,11 +426,14 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
SE->forgetTopmostLoop(&L);
|
|
|
|
SE->forgetTopmostLoop(&L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// Split the preheader, so that we know that there is a safe place to insert
|
|
|
|
// Split the preheader, so that we know that there is a safe place to insert
|
|
|
|
// the conditional branch. We will change the preheader to have a conditional
|
|
|
|
// the conditional branch. We will change the preheader to have a conditional
|
|
|
|
// branch on LoopCond.
|
|
|
|
// branch on LoopCond.
|
|
|
|
BasicBlock *OldPH = L.getLoopPreheader();
|
|
|
|
BasicBlock *OldPH = L.getLoopPreheader();
|
|
|
|
BasicBlock *NewPH = SplitEdge(OldPH, L.getHeader(), &DT, &LI);
|
|
|
|
BasicBlock *NewPH = SplitEdge(OldPH, L.getHeader(), &DT, &LI, MSSAU);
|
|
|
|
|
|
|
|
|
|
|
|
// Now that we have a place to insert the conditional branch, create a place
|
|
|
|
// Now that we have a place to insert the conditional branch, create a place
|
|
|
|
// to branch to: this is the exit block out of the loop that we are
|
|
|
|
// to branch to: this is the exit block out of the loop that we are
|
|
|
@ -439,9 +445,13 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
"A branch's parent isn't a predecessor!");
|
|
|
|
"A branch's parent isn't a predecessor!");
|
|
|
|
UnswitchedBB = LoopExitBB;
|
|
|
|
UnswitchedBB = LoopExitBB;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
UnswitchedBB = SplitBlock(LoopExitBB, &LoopExitBB->front(), &DT, &LI);
|
|
|
|
UnswitchedBB =
|
|
|
|
|
|
|
|
SplitBlock(LoopExitBB, &LoopExitBB->front(), &DT, &LI, MSSAU);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// Actually move the invariant uses into the unswitched position. If possible,
|
|
|
|
// Actually move the invariant uses into the unswitched position. If possible,
|
|
|
|
// we do this by moving the instructions, but when doing partial unswitching
|
|
|
|
// we do this by moving the instructions, but when doing partial unswitching
|
|
|
|
// we do it by building a new merge of the values in the unswitched position.
|
|
|
|
// we do it by building a new merge of the values in the unswitched position.
|
|
|
@ -452,12 +462,17 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
// its successors.
|
|
|
|
// its successors.
|
|
|
|
OldPH->getInstList().splice(OldPH->end(), BI.getParent()->getInstList(),
|
|
|
|
OldPH->getInstList().splice(OldPH->end(), BI.getParent()->getInstList(),
|
|
|
|
BI);
|
|
|
|
BI);
|
|
|
|
BI.setSuccessor(LoopExitSuccIdx, UnswitchedBB);
|
|
|
|
if (MSSAU) {
|
|
|
|
BI.setSuccessor(1 - LoopExitSuccIdx, NewPH);
|
|
|
|
// Temporarily clone the terminator, to make MSSA update cheaper by
|
|
|
|
|
|
|
|
// separating "insert edge" updates from "remove edge" ones.
|
|
|
|
|
|
|
|
ParentBB->getInstList().push_back(BI.clone());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Create a new unconditional branch that will continue the loop as a new
|
|
|
|
// Create a new unconditional branch that will continue the loop as a new
|
|
|
|
// terminator.
|
|
|
|
// terminator.
|
|
|
|
BranchInst::Create(ContinueBB, ParentBB);
|
|
|
|
BranchInst::Create(ContinueBB, ParentBB);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
BI.setSuccessor(LoopExitSuccIdx, UnswitchedBB);
|
|
|
|
|
|
|
|
BI.setSuccessor(1 - LoopExitSuccIdx, NewPH);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Only unswitching a subset of inputs to the condition, so we will need to
|
|
|
|
// Only unswitching a subset of inputs to the condition, so we will need to
|
|
|
|
// build a new branch that merges the invariant inputs.
|
|
|
|
// build a new branch that merges the invariant inputs.
|
|
|
@ -473,6 +488,32 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
*UnswitchedBB, *NewPH);
|
|
|
|
*UnswitchedBB, *NewPH);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Update the dominator tree with the added edge.
|
|
|
|
|
|
|
|
DT.insertEdge(OldPH, UnswitchedBB);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// After the dominator tree was updated with the added edge, update MemorySSA
|
|
|
|
|
|
|
|
// if available.
|
|
|
|
|
|
|
|
if (MSSAU) {
|
|
|
|
|
|
|
|
SmallVector<CFGUpdate, 1> Updates;
|
|
|
|
|
|
|
|
Updates.push_back({cfg::UpdateKind::Insert, OldPH, UnswitchedBB});
|
|
|
|
|
|
|
|
MSSAU->applyInsertUpdates(Updates, DT);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Finish updating dominator tree and memory ssa for full unswitch.
|
|
|
|
|
|
|
|
if (FullUnswitch) {
|
|
|
|
|
|
|
|
if (MSSAU) {
|
|
|
|
|
|
|
|
// Remove the cloned branch instruction.
|
|
|
|
|
|
|
|
ParentBB->getTerminator()->eraseFromParent();
|
|
|
|
|
|
|
|
// Create unconditional branch now.
|
|
|
|
|
|
|
|
BranchInst::Create(ContinueBB, ParentBB);
|
|
|
|
|
|
|
|
MSSAU->removeEdge(ParentBB, LoopExitBB);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
DT.deleteEdge(ParentBB, LoopExitBB);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// Rewrite the relevant PHI nodes.
|
|
|
|
// Rewrite the relevant PHI nodes.
|
|
|
|
if (UnswitchedBB == LoopExitBB)
|
|
|
|
if (UnswitchedBB == LoopExitBB)
|
|
|
|
rewritePHINodesForUnswitchedExitBlock(*UnswitchedBB, *ParentBB, *OldPH);
|
|
|
|
rewritePHINodesForUnswitchedExitBlock(*UnswitchedBB, *ParentBB, *OldPH);
|
|
|
@ -480,13 +521,6 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
rewritePHINodesForExitAndUnswitchedBlocks(*LoopExitBB, *UnswitchedBB,
|
|
|
|
rewritePHINodesForExitAndUnswitchedBlocks(*LoopExitBB, *UnswitchedBB,
|
|
|
|
*ParentBB, *OldPH, FullUnswitch);
|
|
|
|
*ParentBB, *OldPH, FullUnswitch);
|
|
|
|
|
|
|
|
|
|
|
|
// Now we need to update the dominator tree.
|
|
|
|
|
|
|
|
SmallVector<DominatorTree::UpdateType, 2> DTUpdates;
|
|
|
|
|
|
|
|
DTUpdates.push_back({DT.Insert, OldPH, UnswitchedBB});
|
|
|
|
|
|
|
|
if (FullUnswitch)
|
|
|
|
|
|
|
|
DTUpdates.push_back({DT.Delete, ParentBB, LoopExitBB});
|
|
|
|
|
|
|
|
DT.applyUpdates(DTUpdates);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The constant we can replace all of our invariants with inside the loop
|
|
|
|
// The constant we can replace all of our invariants with inside the loop
|
|
|
|
// body. If any of the invariants have a value other than this the loop won't
|
|
|
|
// body. If any of the invariants have a value other than this the loop won't
|
|
|
|
// be entered.
|
|
|
|
// be entered.
|
|
|
@ -537,7 +571,8 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
|
|
|
|
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
|
|
|
|
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
|
|
|
|
/// invalidated by this.
|
|
|
|
/// invalidated by this.
|
|
|
|
static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
LoopInfo &LI, ScalarEvolution *SE) {
|
|
|
|
LoopInfo &LI, ScalarEvolution *SE,
|
|
|
|
|
|
|
|
MemorySSAUpdater *MSSAU) {
|
|
|
|
LLVM_DEBUG(dbgs() << " Trying to unswitch switch: " << SI << "\n");
|
|
|
|
LLVM_DEBUG(dbgs() << " Trying to unswitch switch: " << SI << "\n");
|
|
|
|
Value *LoopCond = SI.getCondition();
|
|
|
|
Value *LoopCond = SI.getCondition();
|
|
|
|
|
|
|
|
|
|
|
@ -564,6 +599,9 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
|
|
|
|
|
|
|
|
LLVM_DEBUG(dbgs() << " unswitching trivial switch...\n");
|
|
|
|
LLVM_DEBUG(dbgs() << " unswitching trivial switch...\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// We may need to invalidate SCEVs for the outermost loop reached by any of
|
|
|
|
// We may need to invalidate SCEVs for the outermost loop reached by any of
|
|
|
|
// the exits.
|
|
|
|
// the exits.
|
|
|
|
Loop *OuterL = &L;
|
|
|
|
Loop *OuterL = &L;
|
|
|
@ -626,7 +664,7 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
// Split the preheader, so that we know that there is a safe place to insert
|
|
|
|
// Split the preheader, so that we know that there is a safe place to insert
|
|
|
|
// the switch.
|
|
|
|
// the switch.
|
|
|
|
BasicBlock *OldPH = L.getLoopPreheader();
|
|
|
|
BasicBlock *OldPH = L.getLoopPreheader();
|
|
|
|
BasicBlock *NewPH = SplitEdge(OldPH, L.getHeader(), &DT, &LI);
|
|
|
|
BasicBlock *NewPH = SplitEdge(OldPH, L.getHeader(), &DT, &LI, MSSAU);
|
|
|
|
OldPH->getTerminator()->eraseFromParent();
|
|
|
|
OldPH->getTerminator()->eraseFromParent();
|
|
|
|
|
|
|
|
|
|
|
|
// Now add the unswitched switch.
|
|
|
|
// Now add the unswitched switch.
|
|
|
@ -649,9 +687,10 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
rewritePHINodesForUnswitchedExitBlock(*DefaultExitBB, *ParentBB, *OldPH);
|
|
|
|
rewritePHINodesForUnswitchedExitBlock(*DefaultExitBB, *ParentBB, *OldPH);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
auto *SplitBB =
|
|
|
|
auto *SplitBB =
|
|
|
|
SplitBlock(DefaultExitBB, &DefaultExitBB->front(), &DT, &LI);
|
|
|
|
SplitBlock(DefaultExitBB, &DefaultExitBB->front(), &DT, &LI, MSSAU);
|
|
|
|
rewritePHINodesForExitAndUnswitchedBlocks(
|
|
|
|
rewritePHINodesForExitAndUnswitchedBlocks(*DefaultExitBB, *SplitBB,
|
|
|
|
*DefaultExitBB, *SplitBB, *ParentBB, *OldPH, /*FullUnswitch*/ true);
|
|
|
|
*ParentBB, *OldPH,
|
|
|
|
|
|
|
|
/*FullUnswitch*/ true);
|
|
|
|
DefaultExitBB = SplitExitBBMap[DefaultExitBB] = SplitBB;
|
|
|
|
DefaultExitBB = SplitExitBBMap[DefaultExitBB] = SplitBB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -675,9 +714,10 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
BasicBlock *&SplitExitBB = SplitExitBBMap[ExitBB];
|
|
|
|
BasicBlock *&SplitExitBB = SplitExitBBMap[ExitBB];
|
|
|
|
if (!SplitExitBB) {
|
|
|
|
if (!SplitExitBB) {
|
|
|
|
// If this is the first time we see this, do the split and remember it.
|
|
|
|
// If this is the first time we see this, do the split and remember it.
|
|
|
|
SplitExitBB = SplitBlock(ExitBB, &ExitBB->front(), &DT, &LI);
|
|
|
|
SplitExitBB = SplitBlock(ExitBB, &ExitBB->front(), &DT, &LI, MSSAU);
|
|
|
|
rewritePHINodesForExitAndUnswitchedBlocks(
|
|
|
|
rewritePHINodesForExitAndUnswitchedBlocks(*ExitBB, *SplitExitBB,
|
|
|
|
*ExitBB, *SplitExitBB, *ParentBB, *OldPH, /*FullUnswitch*/ true);
|
|
|
|
*ParentBB, *OldPH,
|
|
|
|
|
|
|
|
/*FullUnswitch*/ true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Update the case pair to point to the split block.
|
|
|
|
// Update the case pair to point to the split block.
|
|
|
|
CasePair.second = SplitExitBB;
|
|
|
|
CasePair.second = SplitExitBB;
|
|
|
@ -754,6 +794,13 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
DTUpdates.push_back({DT.Insert, OldPH, UnswitchedBB});
|
|
|
|
DTUpdates.push_back({DT.Insert, OldPH, UnswitchedBB});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DT.applyUpdates(DTUpdates);
|
|
|
|
DT.applyUpdates(DTUpdates);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU) {
|
|
|
|
|
|
|
|
MSSAU->applyUpdates(DTUpdates, DT);
|
|
|
|
|
|
|
|
if (VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert(DT.verify(DominatorTree::VerificationLevel::Fast));
|
|
|
|
assert(DT.verify(DominatorTree::VerificationLevel::Fast));
|
|
|
|
|
|
|
|
|
|
|
|
// We may have changed the nesting relationship for this loop so hoist it to
|
|
|
|
// We may have changed the nesting relationship for this loop so hoist it to
|
|
|
@ -779,7 +826,8 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT,
|
|
|
|
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
|
|
|
|
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
|
|
|
|
/// invalidated by this.
|
|
|
|
/// invalidated by this.
|
|
|
|
static bool unswitchAllTrivialConditions(Loop &L, DominatorTree &DT,
|
|
|
|
static bool unswitchAllTrivialConditions(Loop &L, DominatorTree &DT,
|
|
|
|
LoopInfo &LI, ScalarEvolution *SE) {
|
|
|
|
LoopInfo &LI, ScalarEvolution *SE,
|
|
|
|
|
|
|
|
MemorySSAUpdater *MSSAU) {
|
|
|
|
bool Changed = false;
|
|
|
|
bool Changed = false;
|
|
|
|
|
|
|
|
|
|
|
|
// If loop header has only one reachable successor we should keep looking for
|
|
|
|
// If loop header has only one reachable successor we should keep looking for
|
|
|
@ -813,7 +861,7 @@ static bool unswitchAllTrivialConditions(Loop &L, DominatorTree &DT,
|
|
|
|
if (isa<Constant>(SI->getCondition()))
|
|
|
|
if (isa<Constant>(SI->getCondition()))
|
|
|
|
return Changed;
|
|
|
|
return Changed;
|
|
|
|
|
|
|
|
|
|
|
|
if (!unswitchTrivialSwitch(L, *SI, DT, LI, SE))
|
|
|
|
if (!unswitchTrivialSwitch(L, *SI, DT, LI, SE, MSSAU))
|
|
|
|
// Couldn't unswitch this one so we're done.
|
|
|
|
// Couldn't unswitch this one so we're done.
|
|
|
|
return Changed;
|
|
|
|
return Changed;
|
|
|
|
|
|
|
|
|
|
|
@ -845,7 +893,7 @@ static bool unswitchAllTrivialConditions(Loop &L, DominatorTree &DT,
|
|
|
|
|
|
|
|
|
|
|
|
// Found a trivial condition candidate: non-foldable conditional branch. If
|
|
|
|
// Found a trivial condition candidate: non-foldable conditional branch. If
|
|
|
|
// we fail to unswitch this, we can't do anything else that is trivial.
|
|
|
|
// we fail to unswitch this, we can't do anything else that is trivial.
|
|
|
|
if (!unswitchTrivialBranch(L, *BI, DT, LI, SE))
|
|
|
|
if (!unswitchTrivialBranch(L, *BI, DT, LI, SE, MSSAU))
|
|
|
|
return Changed;
|
|
|
|
return Changed;
|
|
|
|
|
|
|
|
|
|
|
|
// Mark that we managed to unswitch something.
|
|
|
|
// Mark that we managed to unswitch something.
|
|
|
@ -898,7 +946,7 @@ static BasicBlock *buildClonedLoopBlocks(
|
|
|
|
const SmallDenseMap<BasicBlock *, BasicBlock *, 16> &DominatingSucc,
|
|
|
|
const SmallDenseMap<BasicBlock *, BasicBlock *, 16> &DominatingSucc,
|
|
|
|
ValueToValueMapTy &VMap,
|
|
|
|
ValueToValueMapTy &VMap,
|
|
|
|
SmallVectorImpl<DominatorTree::UpdateType> &DTUpdates, AssumptionCache &AC,
|
|
|
|
SmallVectorImpl<DominatorTree::UpdateType> &DTUpdates, AssumptionCache &AC,
|
|
|
|
DominatorTree &DT, LoopInfo &LI) {
|
|
|
|
DominatorTree &DT, LoopInfo &LI, MemorySSAUpdater *MSSAU) {
|
|
|
|
SmallVector<BasicBlock *, 4> NewBlocks;
|
|
|
|
SmallVector<BasicBlock *, 4> NewBlocks;
|
|
|
|
NewBlocks.reserve(L.getNumBlocks() + ExitBlocks.size());
|
|
|
|
NewBlocks.reserve(L.getNumBlocks() + ExitBlocks.size());
|
|
|
|
|
|
|
|
|
|
|
@ -943,7 +991,7 @@ static BasicBlock *buildClonedLoopBlocks(
|
|
|
|
// place to merge the CFG, so split the exit first. This is always safe to
|
|
|
|
// place to merge the CFG, so split the exit first. This is always safe to
|
|
|
|
// do because there cannot be any non-loop predecessors of a loop exit in
|
|
|
|
// do because there cannot be any non-loop predecessors of a loop exit in
|
|
|
|
// loop simplified form.
|
|
|
|
// loop simplified form.
|
|
|
|
auto *MergeBB = SplitBlock(ExitBB, &ExitBB->front(), &DT, &LI);
|
|
|
|
auto *MergeBB = SplitBlock(ExitBB, &ExitBB->front(), &DT, &LI, MSSAU);
|
|
|
|
|
|
|
|
|
|
|
|
// Rearrange the names to make it easier to write test cases by having the
|
|
|
|
// Rearrange the names to make it easier to write test cases by having the
|
|
|
|
// exit block carry the suffix rather than the merge block carrying the
|
|
|
|
// exit block carry the suffix rather than the merge block carrying the
|
|
|
@ -1374,7 +1422,7 @@ static void buildClonedLoops(Loop &OrigL, ArrayRef<BasicBlock *> ExitBlocks,
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
|
|
|
|
deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
|
|
|
|
ArrayRef<std::unique_ptr<ValueToValueMapTy>> VMaps,
|
|
|
|
ArrayRef<std::unique_ptr<ValueToValueMapTy>> VMaps,
|
|
|
|
DominatorTree &DT) {
|
|
|
|
DominatorTree &DT, MemorySSAUpdater *MSSAU) {
|
|
|
|
// Find all the dead clones, and remove them from their successors.
|
|
|
|
// Find all the dead clones, and remove them from their successors.
|
|
|
|
SmallVector<BasicBlock *, 16> DeadBlocks;
|
|
|
|
SmallVector<BasicBlock *, 16> DeadBlocks;
|
|
|
|
for (BasicBlock *BB : llvm::concat<BasicBlock *const>(L.blocks(), ExitBlocks))
|
|
|
|
for (BasicBlock *BB : llvm::concat<BasicBlock *const>(L.blocks(), ExitBlocks))
|
|
|
@ -1386,6 +1434,13 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
|
|
|
|
DeadBlocks.push_back(ClonedBB);
|
|
|
|
DeadBlocks.push_back(ClonedBB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove all MemorySSA in the dead blocks
|
|
|
|
|
|
|
|
if (MSSAU) {
|
|
|
|
|
|
|
|
SmallPtrSet<BasicBlock *, 16> DeadBlockSet(DeadBlocks.begin(),
|
|
|
|
|
|
|
|
DeadBlocks.end());
|
|
|
|
|
|
|
|
MSSAU->removeBlocks(DeadBlockSet);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Drop any remaining references to break cycles.
|
|
|
|
// Drop any remaining references to break cycles.
|
|
|
|
for (BasicBlock *BB : DeadBlocks)
|
|
|
|
for (BasicBlock *BB : DeadBlocks)
|
|
|
|
BB->dropAllReferences();
|
|
|
|
BB->dropAllReferences();
|
|
|
@ -1394,10 +1449,10 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
|
|
|
|
BB->eraseFromParent();
|
|
|
|
BB->eraseFromParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void deleteDeadBlocksFromLoop(Loop &L,
|
|
|
|
deleteDeadBlocksFromLoop(Loop &L,
|
|
|
|
|
|
|
|
SmallVectorImpl<BasicBlock *> &ExitBlocks,
|
|
|
|
SmallVectorImpl<BasicBlock *> &ExitBlocks,
|
|
|
|
DominatorTree &DT, LoopInfo &LI) {
|
|
|
|
DominatorTree &DT, LoopInfo &LI,
|
|
|
|
|
|
|
|
MemorySSAUpdater *MSSAU) {
|
|
|
|
// Find all the dead blocks tied to this loop, and remove them from their
|
|
|
|
// Find all the dead blocks tied to this loop, and remove them from their
|
|
|
|
// successors.
|
|
|
|
// successors.
|
|
|
|
SmallPtrSet<BasicBlock *, 16> DeadBlockSet;
|
|
|
|
SmallPtrSet<BasicBlock *, 16> DeadBlockSet;
|
|
|
@ -1418,6 +1473,10 @@ deleteDeadBlocksFromLoop(Loop &L,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove all MemorySSA in the dead blocks
|
|
|
|
|
|
|
|
if (MSSAU)
|
|
|
|
|
|
|
|
MSSAU->removeBlocks(DeadBlockSet);
|
|
|
|
|
|
|
|
|
|
|
|
// Filter out the dead blocks from the exit blocks list so that it can be
|
|
|
|
// Filter out the dead blocks from the exit blocks list so that it can be
|
|
|
|
// used in the caller.
|
|
|
|
// used in the caller.
|
|
|
|
llvm::erase_if(ExitBlocks,
|
|
|
|
llvm::erase_if(ExitBlocks,
|
|
|
@ -1817,7 +1876,7 @@ static void unswitchNontrivialInvariants(
|
|
|
|
Loop &L, Instruction &TI, ArrayRef<Value *> Invariants,
|
|
|
|
Loop &L, Instruction &TI, ArrayRef<Value *> Invariants,
|
|
|
|
SmallVectorImpl<BasicBlock *> &ExitBlocks, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
SmallVectorImpl<BasicBlock *> &ExitBlocks, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
AssumptionCache &AC, function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
|
|
|
|
AssumptionCache &AC, function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
|
|
|
|
ScalarEvolution *SE) {
|
|
|
|
ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
|
|
|
|
auto *ParentBB = TI.getParent();
|
|
|
|
auto *ParentBB = TI.getParent();
|
|
|
|
BranchInst *BI = dyn_cast<BranchInst>(&TI);
|
|
|
|
BranchInst *BI = dyn_cast<BranchInst>(&TI);
|
|
|
|
SwitchInst *SI = BI ? nullptr : cast<SwitchInst>(&TI);
|
|
|
|
SwitchInst *SI = BI ? nullptr : cast<SwitchInst>(&TI);
|
|
|
@ -1834,6 +1893,9 @@ static void unswitchNontrivialInvariants(
|
|
|
|
assert(isa<Instruction>(BI->getCondition()) &&
|
|
|
|
assert(isa<Instruction>(BI->getCondition()) &&
|
|
|
|
"Partial unswitching requires an instruction as the condition!");
|
|
|
|
"Partial unswitching requires an instruction as the condition!");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// Constant and BBs tracking the cloned and continuing successor. When we are
|
|
|
|
// Constant and BBs tracking the cloned and continuing successor. When we are
|
|
|
|
// unswitching the entire condition, this can just be trivially chosen to
|
|
|
|
// unswitching the entire condition, this can just be trivially chosen to
|
|
|
|
// unswitch towards `true`. However, when we are unswitching a set of
|
|
|
|
// unswitch towards `true`. However, when we are unswitching a set of
|
|
|
@ -1874,6 +1936,10 @@ static void unswitchNontrivialInvariants(
|
|
|
|
|
|
|
|
|
|
|
|
// Compute the parent loop now before we start hacking on things.
|
|
|
|
// Compute the parent loop now before we start hacking on things.
|
|
|
|
Loop *ParentL = L.getParentLoop();
|
|
|
|
Loop *ParentL = L.getParentLoop();
|
|
|
|
|
|
|
|
// Get blocks in RPO order for MSSA update, before changing the CFG.
|
|
|
|
|
|
|
|
LoopBlocksRPO LBRPO(&L);
|
|
|
|
|
|
|
|
if (MSSAU)
|
|
|
|
|
|
|
|
LBRPO.perform(&LI);
|
|
|
|
|
|
|
|
|
|
|
|
// Compute the outer-most loop containing one of our exit blocks. This is the
|
|
|
|
// Compute the outer-most loop containing one of our exit blocks. This is the
|
|
|
|
// furthest up our loopnest which can be mutated, which we will use below to
|
|
|
|
// furthest up our loopnest which can be mutated, which we will use below to
|
|
|
@ -1923,7 +1989,7 @@ static void unswitchNontrivialInvariants(
|
|
|
|
// between the unswitched versions, and we will have a new preheader for the
|
|
|
|
// between the unswitched versions, and we will have a new preheader for the
|
|
|
|
// original loop.
|
|
|
|
// original loop.
|
|
|
|
BasicBlock *SplitBB = L.getLoopPreheader();
|
|
|
|
BasicBlock *SplitBB = L.getLoopPreheader();
|
|
|
|
BasicBlock *LoopPH = SplitEdge(SplitBB, L.getHeader(), &DT, &LI);
|
|
|
|
BasicBlock *LoopPH = SplitEdge(SplitBB, L.getHeader(), &DT, &LI, MSSAU);
|
|
|
|
|
|
|
|
|
|
|
|
// Keep track of the dominator tree updates needed.
|
|
|
|
// Keep track of the dominator tree updates needed.
|
|
|
|
SmallVector<DominatorTree::UpdateType, 4> DTUpdates;
|
|
|
|
SmallVector<DominatorTree::UpdateType, 4> DTUpdates;
|
|
|
@ -1936,7 +2002,7 @@ static void unswitchNontrivialInvariants(
|
|
|
|
VMaps.emplace_back(new ValueToValueMapTy());
|
|
|
|
VMaps.emplace_back(new ValueToValueMapTy());
|
|
|
|
ClonedPHs[SuccBB] = buildClonedLoopBlocks(
|
|
|
|
ClonedPHs[SuccBB] = buildClonedLoopBlocks(
|
|
|
|
L, LoopPH, SplitBB, ExitBlocks, ParentBB, SuccBB, RetainedSuccBB,
|
|
|
|
L, LoopPH, SplitBB, ExitBlocks, ParentBB, SuccBB, RetainedSuccBB,
|
|
|
|
DominatingSucc, *VMaps.back(), DTUpdates, AC, DT, LI);
|
|
|
|
DominatingSucc, *VMaps.back(), DTUpdates, AC, DT, LI, MSSAU);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The stitching of the branched code back together depends on whether we're
|
|
|
|
// The stitching of the branched code back together depends on whether we're
|
|
|
@ -1944,7 +2010,63 @@ static void unswitchNontrivialInvariants(
|
|
|
|
// nuke the initial terminator placed in the split block.
|
|
|
|
// nuke the initial terminator placed in the split block.
|
|
|
|
SplitBB->getTerminator()->eraseFromParent();
|
|
|
|
SplitBB->getTerminator()->eraseFromParent();
|
|
|
|
if (FullUnswitch) {
|
|
|
|
if (FullUnswitch) {
|
|
|
|
// First we need to unhook the successor relationship as we'll be replacing
|
|
|
|
// Splice the terminator from the original loop and rewrite its
|
|
|
|
|
|
|
|
// successors.
|
|
|
|
|
|
|
|
SplitBB->getInstList().splice(SplitBB->end(), ParentBB->getInstList(), TI);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Keep a clone of the terminator for MSSA updates.
|
|
|
|
|
|
|
|
Instruction *NewTI = TI.clone();
|
|
|
|
|
|
|
|
ParentBB->getInstList().push_back(NewTI);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// First wire up the moved terminator to the preheaders.
|
|
|
|
|
|
|
|
if (BI) {
|
|
|
|
|
|
|
|
BasicBlock *ClonedPH = ClonedPHs.begin()->second;
|
|
|
|
|
|
|
|
BI->setSuccessor(ClonedSucc, ClonedPH);
|
|
|
|
|
|
|
|
BI->setSuccessor(1 - ClonedSucc, LoopPH);
|
|
|
|
|
|
|
|
DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
assert(SI && "Must either be a branch or switch!");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Walk the cases and directly update their successors.
|
|
|
|
|
|
|
|
assert(SI->getDefaultDest() == RetainedSuccBB &&
|
|
|
|
|
|
|
|
"Not retaining default successor!");
|
|
|
|
|
|
|
|
SI->setDefaultDest(LoopPH);
|
|
|
|
|
|
|
|
for (auto &Case : SI->cases())
|
|
|
|
|
|
|
|
if (Case.getCaseSuccessor() == RetainedSuccBB)
|
|
|
|
|
|
|
|
Case.setSuccessor(LoopPH);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
Case.setSuccessor(ClonedPHs.find(Case.getCaseSuccessor())->second);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We need to use the set to populate domtree updates as even when there
|
|
|
|
|
|
|
|
// are multiple cases pointing at the same successor we only want to
|
|
|
|
|
|
|
|
// remove and insert one edge in the domtree.
|
|
|
|
|
|
|
|
for (BasicBlock *SuccBB : UnswitchedSuccBBs)
|
|
|
|
|
|
|
|
DTUpdates.push_back(
|
|
|
|
|
|
|
|
{DominatorTree::Insert, SplitBB, ClonedPHs.find(SuccBB)->second});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU) {
|
|
|
|
|
|
|
|
DT.applyUpdates(DTUpdates);
|
|
|
|
|
|
|
|
DTUpdates.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove all but one edge to the retained block and all unswitched
|
|
|
|
|
|
|
|
// blocks. This is to avoid having duplicate entries in the cloned Phis,
|
|
|
|
|
|
|
|
// when we know we only keep a single edge for each case.
|
|
|
|
|
|
|
|
MSSAU->removeDuplicatePhiEdgesBetween(ParentBB, RetainedSuccBB);
|
|
|
|
|
|
|
|
for (BasicBlock *SuccBB : UnswitchedSuccBBs)
|
|
|
|
|
|
|
|
MSSAU->removeDuplicatePhiEdgesBetween(ParentBB, SuccBB);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto &VMap : VMaps)
|
|
|
|
|
|
|
|
MSSAU->updateForClonedLoop(LBRPO, ExitBlocks, *VMap,
|
|
|
|
|
|
|
|
/*IgnoreIncomingWithNoClones=*/true);
|
|
|
|
|
|
|
|
MSSAU->updateExitBlocksForClonedLoop(ExitBlocks, VMaps, DT);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove all edges to unswitched blocks.
|
|
|
|
|
|
|
|
for (BasicBlock *SuccBB : UnswitchedSuccBBs)
|
|
|
|
|
|
|
|
MSSAU->removeEdge(ParentBB, SuccBB);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now unhook the successor relationship as we'll be replacing
|
|
|
|
// the terminator with a direct branch. This is much simpler for branches
|
|
|
|
// the terminator with a direct branch. This is much simpler for branches
|
|
|
|
// than switches so we handle those first.
|
|
|
|
// than switches so we handle those first.
|
|
|
|
if (BI) {
|
|
|
|
if (BI) {
|
|
|
@ -1962,9 +2084,10 @@ static void unswitchNontrivialInvariants(
|
|
|
|
// is a duplicate edge to the retained successor as the retained successor
|
|
|
|
// is a duplicate edge to the retained successor as the retained successor
|
|
|
|
// is always the default successor and as we'll replace this with a direct
|
|
|
|
// is always the default successor and as we'll replace this with a direct
|
|
|
|
// branch we no longer need the duplicate entries in the PHI nodes.
|
|
|
|
// branch we no longer need the duplicate entries in the PHI nodes.
|
|
|
|
assert(SI->getDefaultDest() == RetainedSuccBB &&
|
|
|
|
SwitchInst *NewSI = cast<SwitchInst>(NewTI);
|
|
|
|
|
|
|
|
assert(NewSI->getDefaultDest() == RetainedSuccBB &&
|
|
|
|
"Not retaining default successor!");
|
|
|
|
"Not retaining default successor!");
|
|
|
|
for (auto &Case : SI->cases())
|
|
|
|
for (auto &Case : NewSI->cases())
|
|
|
|
Case.getCaseSuccessor()->removePredecessor(
|
|
|
|
Case.getCaseSuccessor()->removePredecessor(
|
|
|
|
ParentBB,
|
|
|
|
ParentBB,
|
|
|
|
/*DontDeleteUselessPHIs*/ true);
|
|
|
|
/*DontDeleteUselessPHIs*/ true);
|
|
|
@ -1976,34 +2099,8 @@ static void unswitchNontrivialInvariants(
|
|
|
|
DTUpdates.push_back({DominatorTree::Delete, ParentBB, SuccBB});
|
|
|
|
DTUpdates.push_back({DominatorTree::Delete, ParentBB, SuccBB});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now that we've unhooked the successor relationship, splice the terminator
|
|
|
|
// After MSSAU update, remove the cloned terminator instruction NewTI.
|
|
|
|
// from the original loop to the split.
|
|
|
|
ParentBB->getTerminator()->eraseFromParent();
|
|
|
|
SplitBB->getInstList().splice(SplitBB->end(), ParentBB->getInstList(), TI);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now wire up the terminator to the preheaders.
|
|
|
|
|
|
|
|
if (BI) {
|
|
|
|
|
|
|
|
BasicBlock *ClonedPH = ClonedPHs.begin()->second;
|
|
|
|
|
|
|
|
BI->setSuccessor(ClonedSucc, ClonedPH);
|
|
|
|
|
|
|
|
BI->setSuccessor(1 - ClonedSucc, LoopPH);
|
|
|
|
|
|
|
|
DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
assert(SI && "Must either be a branch or switch!");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Walk the cases and directly update their successors.
|
|
|
|
|
|
|
|
SI->setDefaultDest(LoopPH);
|
|
|
|
|
|
|
|
for (auto &Case : SI->cases())
|
|
|
|
|
|
|
|
if (Case.getCaseSuccessor() == RetainedSuccBB)
|
|
|
|
|
|
|
|
Case.setSuccessor(LoopPH);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
Case.setSuccessor(ClonedPHs.find(Case.getCaseSuccessor())->second);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We need to use the set to populate domtree updates as even when there
|
|
|
|
|
|
|
|
// are multiple cases pointing at the same successor we only want to
|
|
|
|
|
|
|
|
// remove and insert one edge in the domtree.
|
|
|
|
|
|
|
|
for (BasicBlock *SuccBB : UnswitchedSuccBBs)
|
|
|
|
|
|
|
|
DTUpdates.push_back(
|
|
|
|
|
|
|
|
{DominatorTree::Insert, SplitBB, ClonedPHs.find(SuccBB)->second});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a new unconditional branch to the continuing block (as opposed to
|
|
|
|
// Create a new unconditional branch to the continuing block (as opposed to
|
|
|
|
// the one cloned).
|
|
|
|
// the one cloned).
|
|
|
@ -2022,12 +2119,19 @@ static void unswitchNontrivialInvariants(
|
|
|
|
|
|
|
|
|
|
|
|
// Apply the updates accumulated above to get an up-to-date dominator tree.
|
|
|
|
// Apply the updates accumulated above to get an up-to-date dominator tree.
|
|
|
|
DT.applyUpdates(DTUpdates);
|
|
|
|
DT.applyUpdates(DTUpdates);
|
|
|
|
|
|
|
|
if (!FullUnswitch && MSSAU) {
|
|
|
|
|
|
|
|
// Update MSSA for partial unswitch, after DT update.
|
|
|
|
|
|
|
|
SmallVector<CFGUpdate, 1> Updates;
|
|
|
|
|
|
|
|
Updates.push_back(
|
|
|
|
|
|
|
|
{cfg::UpdateKind::Insert, SplitBB, ClonedPHs.begin()->second});
|
|
|
|
|
|
|
|
MSSAU->applyInsertUpdates(Updates, DT);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now that we have an accurate dominator tree, first delete the dead cloned
|
|
|
|
// Now that we have an accurate dominator tree, first delete the dead cloned
|
|
|
|
// blocks so that we can accurately build any cloned loops. It is important to
|
|
|
|
// blocks so that we can accurately build any cloned loops. It is important to
|
|
|
|
// not delete the blocks from the original loop yet because we still want to
|
|
|
|
// not delete the blocks from the original loop yet because we still want to
|
|
|
|
// reference the original loop to understand the cloned loop's structure.
|
|
|
|
// reference the original loop to understand the cloned loop's structure.
|
|
|
|
deleteDeadClonedBlocks(L, ExitBlocks, VMaps, DT);
|
|
|
|
deleteDeadClonedBlocks(L, ExitBlocks, VMaps, DT, MSSAU);
|
|
|
|
|
|
|
|
|
|
|
|
// Build the cloned loop structure itself. This may be substantially
|
|
|
|
// Build the cloned loop structure itself. This may be substantially
|
|
|
|
// different from the original structure due to the simplified CFG. This also
|
|
|
|
// different from the original structure due to the simplified CFG. This also
|
|
|
@ -2039,10 +2143,17 @@ static void unswitchNontrivialInvariants(
|
|
|
|
// Now that our cloned loops have been built, we can update the original loop.
|
|
|
|
// Now that our cloned loops have been built, we can update the original loop.
|
|
|
|
// First we delete the dead blocks from it and then we rebuild the loop
|
|
|
|
// First we delete the dead blocks from it and then we rebuild the loop
|
|
|
|
// structure taking these deletions into account.
|
|
|
|
// structure taking these deletions into account.
|
|
|
|
deleteDeadBlocksFromLoop(L, ExitBlocks, DT, LI);
|
|
|
|
deleteDeadBlocksFromLoop(L, ExitBlocks, DT, LI, MSSAU);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
SmallVector<Loop *, 4> HoistedLoops;
|
|
|
|
SmallVector<Loop *, 4> HoistedLoops;
|
|
|
|
bool IsStillLoop = rebuildLoopAfterUnswitch(L, ExitBlocks, LI, HoistedLoops);
|
|
|
|
bool IsStillLoop = rebuildLoopAfterUnswitch(L, ExitBlocks, LI, HoistedLoops);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// This transformation has a high risk of corrupting the dominator tree, and
|
|
|
|
// This transformation has a high risk of corrupting the dominator tree, and
|
|
|
|
// the below steps to rebuild loop structures will result in hard to debug
|
|
|
|
// the below steps to rebuild loop structures will result in hard to debug
|
|
|
|
// errors in that case so verify that the dominator tree is sane first.
|
|
|
|
// errors in that case so verify that the dominator tree is sane first.
|
|
|
@ -2167,6 +2278,9 @@ static void unswitchNontrivialInvariants(
|
|
|
|
SibLoops.push_back(UpdatedL);
|
|
|
|
SibLoops.push_back(UpdatedL);
|
|
|
|
UnswitchCB(IsStillLoop, SibLoops);
|
|
|
|
UnswitchCB(IsStillLoop, SibLoops);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
++NumBranches;
|
|
|
|
++NumBranches;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -2227,11 +2341,16 @@ computeDomSubtreeCost(DomTreeNode &N,
|
|
|
|
static BranchInst *
|
|
|
|
static BranchInst *
|
|
|
|
turnGuardIntoBranch(IntrinsicInst *GI, Loop &L,
|
|
|
|
turnGuardIntoBranch(IntrinsicInst *GI, Loop &L,
|
|
|
|
SmallVectorImpl<BasicBlock *> &ExitBlocks,
|
|
|
|
SmallVectorImpl<BasicBlock *> &ExitBlocks,
|
|
|
|
DominatorTree &DT, LoopInfo &LI) {
|
|
|
|
DominatorTree &DT, LoopInfo &LI, MemorySSAUpdater *MSSAU) {
|
|
|
|
SmallVector<DominatorTree::UpdateType, 4> DTUpdates;
|
|
|
|
SmallVector<DominatorTree::UpdateType, 4> DTUpdates;
|
|
|
|
LLVM_DEBUG(dbgs() << "Turning " << *GI << " into a branch.\n");
|
|
|
|
LLVM_DEBUG(dbgs() << "Turning " << *GI << " into a branch.\n");
|
|
|
|
BasicBlock *CheckBB = GI->getParent();
|
|
|
|
BasicBlock *CheckBB = GI->getParent();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU && VerifyMemorySSA) {
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->dump();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Remove all CheckBB's successors from DomTree. A block can be seen among
|
|
|
|
// Remove all CheckBB's successors from DomTree. A block can be seen among
|
|
|
|
// successors more than once, but for DomTree it should be added only once.
|
|
|
|
// successors more than once, but for DomTree it should be added only once.
|
|
|
|
SmallPtrSet<BasicBlock *, 4> Successors;
|
|
|
|
SmallPtrSet<BasicBlock *, 4> Successors;
|
|
|
@ -2249,10 +2368,14 @@ turnGuardIntoBranch(IntrinsicInst *GI, Loop &L,
|
|
|
|
BasicBlock *GuardedBlock = CheckBI->getSuccessor(0);
|
|
|
|
BasicBlock *GuardedBlock = CheckBI->getSuccessor(0);
|
|
|
|
GuardedBlock->setName("guarded");
|
|
|
|
GuardedBlock->setName("guarded");
|
|
|
|
CheckBI->getSuccessor(1)->setName("deopt");
|
|
|
|
CheckBI->getSuccessor(1)->setName("deopt");
|
|
|
|
|
|
|
|
BasicBlock *DeoptBlock = CheckBI->getSuccessor(1);
|
|
|
|
|
|
|
|
|
|
|
|
// We now have a new exit block.
|
|
|
|
// We now have a new exit block.
|
|
|
|
ExitBlocks.push_back(CheckBI->getSuccessor(1));
|
|
|
|
ExitBlocks.push_back(CheckBI->getSuccessor(1));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU)
|
|
|
|
|
|
|
|
MSSAU->moveAllAfterSpliceBlocks(CheckBB, GuardedBlock, GI);
|
|
|
|
|
|
|
|
|
|
|
|
GI->moveBefore(DeoptBlockTerm);
|
|
|
|
GI->moveBefore(DeoptBlockTerm);
|
|
|
|
GI->setArgOperand(0, ConstantInt::getFalse(GI->getContext()));
|
|
|
|
GI->setArgOperand(0, ConstantInt::getFalse(GI->getContext()));
|
|
|
|
|
|
|
|
|
|
|
@ -2270,6 +2393,13 @@ turnGuardIntoBranch(IntrinsicInst *GI, Loop &L,
|
|
|
|
// Inform LI of a new loop block.
|
|
|
|
// Inform LI of a new loop block.
|
|
|
|
L.addBasicBlockToLoop(GuardedBlock, LI);
|
|
|
|
L.addBasicBlockToLoop(GuardedBlock, LI);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSAU) {
|
|
|
|
|
|
|
|
MemoryDef *MD = cast<MemoryDef>(MSSAU->getMemorySSA()->getMemoryAccess(GI));
|
|
|
|
|
|
|
|
MSSAU->moveToPlace(MD, DeoptBlock, MemorySSA::End);
|
|
|
|
|
|
|
|
if (VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSAU->getMemorySSA()->verifyMemorySSA();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
++NumGuards;
|
|
|
|
++NumGuards;
|
|
|
|
return CheckBI;
|
|
|
|
return CheckBI;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -2363,7 +2493,7 @@ static bool
|
|
|
|
unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
AssumptionCache &AC, TargetTransformInfo &TTI,
|
|
|
|
AssumptionCache &AC, TargetTransformInfo &TTI,
|
|
|
|
function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
|
|
|
|
function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
|
|
|
|
ScalarEvolution *SE) {
|
|
|
|
ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
|
|
|
|
// Collect all invariant conditions within this loop (as opposed to an inner
|
|
|
|
// Collect all invariant conditions within this loop (as opposed to an inner
|
|
|
|
// loop which would be handled when visiting that inner loop).
|
|
|
|
// loop which would be handled when visiting that inner loop).
|
|
|
|
SmallVector<std::pair<Instruction *, TinyPtrVector<Value *>>, 4>
|
|
|
|
SmallVector<std::pair<Instruction *, TinyPtrVector<Value *>>, 4>
|
|
|
@ -2605,13 +2735,13 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
// If the best candidate is a guard, turn it into a branch.
|
|
|
|
// If the best candidate is a guard, turn it into a branch.
|
|
|
|
if (isGuard(BestUnswitchTI))
|
|
|
|
if (isGuard(BestUnswitchTI))
|
|
|
|
BestUnswitchTI = turnGuardIntoBranch(cast<IntrinsicInst>(BestUnswitchTI), L,
|
|
|
|
BestUnswitchTI = turnGuardIntoBranch(cast<IntrinsicInst>(BestUnswitchTI), L,
|
|
|
|
ExitBlocks, DT, LI);
|
|
|
|
ExitBlocks, DT, LI, MSSAU);
|
|
|
|
|
|
|
|
|
|
|
|
LLVM_DEBUG(dbgs() << " Unswitching non-trivial (cost = "
|
|
|
|
LLVM_DEBUG(dbgs() << " Unswitching non-trivial (cost = "
|
|
|
|
<< BestUnswitchCost << ") terminator: " << *BestUnswitchTI
|
|
|
|
<< BestUnswitchCost << ") terminator: " << *BestUnswitchTI
|
|
|
|
<< "\n");
|
|
|
|
<< "\n");
|
|
|
|
unswitchNontrivialInvariants(L, *BestUnswitchTI, BestUnswitchInvariants,
|
|
|
|
unswitchNontrivialInvariants(L, *BestUnswitchTI, BestUnswitchInvariants,
|
|
|
|
ExitBlocks, DT, LI, AC, UnswitchCB, SE);
|
|
|
|
ExitBlocks, DT, LI, AC, UnswitchCB, SE, MSSAU);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -2624,6 +2754,7 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// The `DT`, `LI`, `AC`, `TTI` parameters are required analyses that are also
|
|
|
|
/// The `DT`, `LI`, `AC`, `TTI` parameters are required analyses that are also
|
|
|
|
/// updated based on the unswitch.
|
|
|
|
/// updated based on the unswitch.
|
|
|
|
|
|
|
|
/// The `MSSA` analysis is also updated if valid (i.e. its use is enabled).
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// If either `NonTrivial` is true or the flag `EnableNonTrivialUnswitch` is
|
|
|
|
/// If either `NonTrivial` is true or the flag `EnableNonTrivialUnswitch` is
|
|
|
|
/// true, we will attempt to do non-trivial unswitching as well as trivial
|
|
|
|
/// true, we will attempt to do non-trivial unswitching as well as trivial
|
|
|
@ -2639,7 +2770,7 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
AssumptionCache &AC, TargetTransformInfo &TTI,
|
|
|
|
AssumptionCache &AC, TargetTransformInfo &TTI,
|
|
|
|
bool NonTrivial,
|
|
|
|
bool NonTrivial,
|
|
|
|
function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
|
|
|
|
function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
|
|
|
|
ScalarEvolution *SE) {
|
|
|
|
ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
|
|
|
|
assert(L.isRecursivelyLCSSAForm(DT, LI) &&
|
|
|
|
assert(L.isRecursivelyLCSSAForm(DT, LI) &&
|
|
|
|
"Loops must be in LCSSA form before unswitching.");
|
|
|
|
"Loops must be in LCSSA form before unswitching.");
|
|
|
|
bool Changed = false;
|
|
|
|
bool Changed = false;
|
|
|
@ -2649,7 +2780,7 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// Try trivial unswitch first before loop over other basic blocks in the loop.
|
|
|
|
// Try trivial unswitch first before loop over other basic blocks in the loop.
|
|
|
|
if (unswitchAllTrivialConditions(L, DT, LI, SE)) {
|
|
|
|
if (unswitchAllTrivialConditions(L, DT, LI, SE, MSSAU)) {
|
|
|
|
// If we unswitched successfully we will want to clean up the loop before
|
|
|
|
// If we unswitched successfully we will want to clean up the loop before
|
|
|
|
// processing it further so just mark it as unswitched and return.
|
|
|
|
// processing it further so just mark it as unswitched and return.
|
|
|
|
UnswitchCB(/*CurrentLoopValid*/ true, {});
|
|
|
|
UnswitchCB(/*CurrentLoopValid*/ true, {});
|
|
|
@ -2670,7 +2801,7 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
|
|
|
|
|
|
|
|
|
|
|
|
// Try to unswitch the best invariant condition. We prefer this full unswitch to
|
|
|
|
// Try to unswitch the best invariant condition. We prefer this full unswitch to
|
|
|
|
// a partial unswitch when possible below the threshold.
|
|
|
|
// a partial unswitch when possible below the threshold.
|
|
|
|
if (unswitchBestCondition(L, DT, LI, AC, TTI, UnswitchCB, SE))
|
|
|
|
if (unswitchBestCondition(L, DT, LI, AC, TTI, UnswitchCB, SE, MSSAU))
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// No other opportunities to unswitch.
|
|
|
|
// No other opportunities to unswitch.
|
|
|
@ -2704,10 +2835,19 @@ PreservedAnalyses SimpleLoopUnswitchPass::run(Loop &L, LoopAnalysisManager &AM,
|
|
|
|
U.markLoopAsDeleted(L, LoopName);
|
|
|
|
U.markLoopAsDeleted(L, LoopName);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Optional<MemorySSAUpdater> MSSAU;
|
|
|
|
|
|
|
|
if (AR.MSSA) {
|
|
|
|
|
|
|
|
MSSAU = MemorySSAUpdater(AR.MSSA);
|
|
|
|
|
|
|
|
if (VerifyMemorySSA)
|
|
|
|
|
|
|
|
AR.MSSA->verifyMemorySSA();
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!unswitchLoop(L, AR.DT, AR.LI, AR.AC, AR.TTI, NonTrivial, UnswitchCB,
|
|
|
|
if (!unswitchLoop(L, AR.DT, AR.LI, AR.AC, AR.TTI, NonTrivial, UnswitchCB,
|
|
|
|
&AR.SE))
|
|
|
|
&AR.SE, MSSAU.hasValue() ? MSSAU.getPointer() : nullptr))
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (AR.MSSA && VerifyMemorySSA)
|
|
|
|
|
|
|
|
AR.MSSA->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// Historically this pass has had issues with the dominator tree so verify it
|
|
|
|
// Historically this pass has had issues with the dominator tree so verify it
|
|
|
|
// in asserts builds.
|
|
|
|
// in asserts builds.
|
|
|
|
assert(AR.DT.verify(DominatorTree::VerificationLevel::Fast));
|
|
|
|
assert(AR.DT.verify(DominatorTree::VerificationLevel::Fast));
|
|
|
@ -2733,6 +2873,10 @@ public:
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
AU.addRequired<AssumptionCacheTracker>();
|
|
|
|
AU.addRequired<AssumptionCacheTracker>();
|
|
|
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
|
|
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
|
|
|
|
|
|
|
if (EnableMSSALoopDependency) {
|
|
|
|
|
|
|
|
AU.addRequired<MemorySSAWrapperPass>();
|
|
|
|
|
|
|
|
AU.addPreserved<MemorySSAWrapperPass>();
|
|
|
|
|
|
|
|
}
|
|
|
|
getLoopAnalysisUsage(AU);
|
|
|
|
getLoopAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -2752,6 +2896,12 @@ bool SimpleLoopUnswitchLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) {
|
|
|
|
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
|
|
|
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
|
|
|
auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
|
|
|
|
auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
|
|
|
|
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
|
|
|
|
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
|
|
|
|
|
|
|
|
MemorySSA *MSSA = nullptr;
|
|
|
|
|
|
|
|
Optional<MemorySSAUpdater> MSSAU;
|
|
|
|
|
|
|
|
if (EnableMSSALoopDependency) {
|
|
|
|
|
|
|
|
MSSA = &getAnalysis<MemorySSAWrapperPass>().getMSSA();
|
|
|
|
|
|
|
|
MSSAU = MemorySSAUpdater(MSSA);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto *SEWP = getAnalysisIfAvailable<ScalarEvolutionWrapperPass>();
|
|
|
|
auto *SEWP = getAnalysisIfAvailable<ScalarEvolutionWrapperPass>();
|
|
|
|
auto *SE = SEWP ? &SEWP->getSE() : nullptr;
|
|
|
|
auto *SE = SEWP ? &SEWP->getSE() : nullptr;
|
|
|
@ -2771,7 +2921,14 @@ bool SimpleLoopUnswitchLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) {
|
|
|
|
LPM.markLoopAsDeleted(*L);
|
|
|
|
LPM.markLoopAsDeleted(*L);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bool Changed = unswitchLoop(*L, DT, LI, AC, TTI, NonTrivial, UnswitchCB, SE);
|
|
|
|
if (MSSA && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSA->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Changed = unswitchLoop(*L, DT, LI, AC, TTI, NonTrivial, UnswitchCB, SE,
|
|
|
|
|
|
|
|
MSSAU.hasValue() ? MSSAU.getPointer() : nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MSSA && VerifyMemorySSA)
|
|
|
|
|
|
|
|
MSSA->verifyMemorySSA();
|
|
|
|
|
|
|
|
|
|
|
|
// If anything was unswitched, also clear any cached information about this
|
|
|
|
// If anything was unswitched, also clear any cached information about this
|
|
|
|
// loop.
|
|
|
|
// loop.
|
|
|
@ -2791,6 +2948,7 @@ INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopPass)
|
|
|
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
|
|
|
|
INITIALIZE_PASS_END(SimpleLoopUnswitchLegacyPass, "simple-loop-unswitch",
|
|
|
|
INITIALIZE_PASS_END(SimpleLoopUnswitchLegacyPass, "simple-loop-unswitch",
|
|
|
|
"Simple unswitch loops", false, false)
|
|
|
|
"Simple unswitch loops", false, false)
|
|
|
|