1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

Update MemorySSA in SimpleLoopUnswitch.

Summary:
Teach SimpleLoopUnswitch to preserve MemorySSA.

Subscribers: sanjoy, jlebar, Prazek, george.burgess.iv, llvm-commits

Differential Revision: https://reviews.llvm.org/D47022

llvm-svn: 348263
This commit is contained in:
Alina Sbirlea 2018-12-04 14:23:37 +00:00
parent 7e5a79b353
commit 7f0355fada
32 changed files with 266 additions and 77 deletions

View File

@ -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)

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
%struct.BLEND_MAP = type { i16, i16, i16, i32, %struct.BLEND_MAP_ENTRY* } %struct.BLEND_MAP = type { i16, i16, i16, i32, %struct.BLEND_MAP_ENTRY* }
%struct.BLEND_MAP_ENTRY = type { float, i8, { [5 x float], [4 x i8] } } %struct.BLEND_MAP_ENTRY = type { float, i8, { [5 x float], [4 x i8] } }

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
define void @init_caller_save() { define void @init_caller_save() {
entry: entry:

View File

@ -1,5 +1,6 @@
; PR1333 ; PR1333
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64" target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64"
target triple = "i686-pc-linux-gnu" target triple = "i686-pc-linux-gnu"

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
; PR1333 ; PR1333
define void @pp_cxx_expression() { define void @pp_cxx_expression() {

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -instcombine -disable-output ; RUN: opt < %s -simple-loop-unswitch -instcombine -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -instcombine -disable-output
@str3 = external constant [3 x i8] ; <[3 x i8]*> [#uses=1] @str3 = external constant [3 x i8] ; <[3 x i8]*> [#uses=1]

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
define i32 @main(i32 %argc, i8** %argv) { define i32 @main(i32 %argc, i8** %argv) {
entry: entry:

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
; PR1559 ; PR1559
target triple = "i686-pc-linux-gnu" target triple = "i686-pc-linux-gnu"

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -instcombine -disable-output ; RUN: opt < %s -simple-loop-unswitch -instcombine -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -instcombine -disable-output
%struct.ClassDef = type { %struct.QByteArray, %struct.QByteArray, %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", i8, i8, %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QMap<QByteArray,QByteArray>", %"struct.QList<ArgumentDef>", %"struct.QMap<QByteArray,QByteArray>", i32, i32 } %struct.ClassDef = type { %struct.QByteArray, %struct.QByteArray, %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", i8, i8, %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QMap<QByteArray,QByteArray>", %"struct.QList<ArgumentDef>", %"struct.QMap<QByteArray,QByteArray>", i32, i32 }
%struct.FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.FILE*, i32, i32, i32, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i32, i32, [40 x i8] } %struct.FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.FILE*, i32, i32, i32, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i32, i32, [40 x i8] }
%struct.Generator = type { %struct.FILE*, %struct.ClassDef*, %"struct.QList<ArgumentDef>", %struct.QByteArray, %"struct.QList<ArgumentDef>" } %struct.Generator = type { %struct.FILE*, %struct.ClassDef*, %"struct.QList<ArgumentDef>", %struct.QByteArray, %"struct.QList<ArgumentDef>" }

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -instcombine -gvn -disable-output ; RUN: opt < %s -simple-loop-unswitch -instcombine -gvn -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -instcombine -gvn -disable-output
; PR2372 ; PR2372
target triple = "i386-pc-linux-gnu" target triple = "i386-pc-linux-gnu"

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch ; RUN: opt < %s -simple-loop-unswitch
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa
; PR8622 ; PR8622
@g_38 = external global i32, align 4 @g_38 = external global i32, align 4

View File

@ -1,4 +1,5 @@
; RUN: opt -simple-loop-unswitch -disable-output < %s ; RUN: opt -simple-loop-unswitch -disable-output < %s
; RUN: opt -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output < %s
; PR10031 ; PR10031
define i32 @test(i32 %command) { define i32 @test(i32 %command) {

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -sroa -simple-loop-unswitch -disable-output ; RUN: opt < %s -sroa -simple-loop-unswitch -disable-output
; RUN: opt < %s -sroa -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
; PR11016 ; PR11016
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-macosx10.7.2" target triple = "x86_64-apple-macosx10.7.2"

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -S -simple-loop-unswitch -verify-loop-info -verify-dom-info | FileCheck %s ; RUN: opt < %s -S -simple-loop-unswitch -verify-loop-info -verify-dom-info | FileCheck %s
; RUN: opt < %s -S -simple-loop-unswitch -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s
; PR12343: -simple-loop-unswitch crash on indirect branch ; PR12343: -simple-loop-unswitch crash on indirect branch
; CHECK: %0 = icmp eq i64 undef, 0 ; CHECK: %0 = icmp eq i64 undef, 0

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
; PR12887 ; PR12887
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu" target triple = "x86_64-unknown-linux-gnu"

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -S | FileCheck %s ; RUN: opt < %s -simple-loop-unswitch -S | FileCheck %s
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
; In cases where two address spaces do not have the same size pointer, the ; In cases where two address spaces do not have the same size pointer, the
; input for the addrspacecast should not be used as a substitute for itself ; input for the addrspacecast should not be used as a substitute for itself

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -S 2>&1 | FileCheck %s ; RUN: opt < %s -simple-loop-unswitch -S 2>&1 | FileCheck %s
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -S 2>&1 | FileCheck %s
; This is to test trivial loop unswitch only happens when trivial condition ; This is to test trivial loop unswitch only happens when trivial condition
; itself is an LIV loop condition (not partial LIV which could occur in and/or). ; itself is an LIV loop condition (not partial LIV which could occur in and/or).

View File

@ -1,4 +1,5 @@
; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s ; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
; RUN: opt -enable-mssa-loop-dependency=true -verify-memoryssa -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
define i32 @test(i32* %A, i1 %C) { define i32 @test(i32* %A, i1 %C) {
entry: entry:

View File

@ -1,4 +1,5 @@
; RUN: opt -S -simple-loop-unswitch < %s | FileCheck %s ; RUN: opt -S -simple-loop-unswitch < %s | FileCheck %s
; RUN: opt -S -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
target triple = "x86_64-pc-win32" target triple = "x86_64-pc-win32"
define void @f(i32 %doit, i1 %x, i1 %y) personality i32 (...)* @__CxxFrameHandler3 { define void @f(i32 %doit, i1 %x, i1 %y) personality i32 (...)* @__CxxFrameHandler3 {

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -S | FileCheck %s ; RUN: opt < %s -simple-loop-unswitch -S | FileCheck %s
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
; This test checks if unswitched condition preserve make.implicit metadata. ; This test checks if unswitched condition preserve make.implicit metadata.
define i32 @test(i1 %cond) { define i32 @test(i1 %cond) {

View File

@ -1,4 +1,5 @@
; RUN: opt < %s -simple-loop-unswitch -disable-output ; RUN: opt < %s -simple-loop-unswitch -disable-output
; RUN: opt < %s -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
define void @test1(i32* %S2) { define void @test1(i32* %S2) {
entry: entry:

View File

@ -1,4 +1,5 @@
; RUN: opt -simple-loop-unswitch -S < %s | FileCheck %s ; RUN: opt -simple-loop-unswitch -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -S < %s | FileCheck %s
define void @f(i32 %n, i32* %ptr) { define void @f(i32 %n, i32* %ptr) {
; CHECK-LABEL: @f( ; CHECK-LABEL: @f(

View File

@ -1,5 +1,6 @@
; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -simple-loop-unswitch-guards -S < %s | FileCheck %s ; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -simple-loop-unswitch-guards -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -simple-loop-unswitch-guards -S < %s | FileCheck %s ; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -simple-loop-unswitch-guards -S < %s | FileCheck %s
; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -simple-loop-unswitch-guards -enable-mssa-loop-dependency=true -verify-memoryssa -S < %s | FileCheck %s
declare void @llvm.experimental.guard(i1, ...) declare void @llvm.experimental.guard(i1, ...)

View File

@ -1,6 +1,7 @@
; REQUIRES: asserts ; REQUIRES: asserts
; RUN: opt -simple-loop-unswitch -disable-output -stats -info-output-file - < %s | FileCheck --check-prefix=STATS %s ; RUN: opt -simple-loop-unswitch -disable-output -stats -info-output-file - < %s | FileCheck --check-prefix=STATS %s
; RUN: opt -simple-loop-unswitch -S < %s | FileCheck %s ; RUN: opt -simple-loop-unswitch -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -S < %s | FileCheck %s
; PR5373 ; PR5373
; Loop unswitching shouldn't trivially unswitch the true case of condition %a ; Loop unswitching shouldn't trivially unswitch the true case of condition %a

View File

@ -1,4 +1,5 @@
; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s ; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
; RUN: opt -enable-mssa-loop-dependency=true -verify-memoryssa -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
declare void @unknown() declare void @unknown()
declare void @unknown2() declare void @unknown2()

View File

@ -2,6 +2,7 @@
; ;
; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -unswitch-threshold=5 -S < %s | FileCheck %s ; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -unswitch-threshold=5 -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -unswitch-threshold=5 -S < %s | FileCheck %s ; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -unswitch-threshold=5 -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -unswitch-threshold=5 -enable-mssa-loop-dependency=true -verify-memoryssa -S < %s | FileCheck %s
declare void @a() declare void @a()
declare void @b() declare void @b()

View File

@ -1,5 +1,6 @@
; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -S < %s | FileCheck %s ; RUN: opt -passes='loop(unswitch),verify<loops>' -enable-nontrivial-unswitch -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -S < %s | FileCheck %s ; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-nontrivial-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -S < %s | FileCheck %s
declare i32 @a() declare i32 @a()
declare i32 @b() declare i32 @b()

View File

@ -1,4 +1,5 @@
; RUN: opt -simple-loop-unswitch -loop-deletion -S < %s | FileCheck %s ; RUN: opt -simple-loop-unswitch -loop-deletion -S < %s | FileCheck %s
; RUN: opt -simple-loop-unswitch -enable-mssa-loop-dependency=true -verify-memoryssa -loop-deletion -S < %s | FileCheck %s
; ;
; Check that when we do unswitching where we re-enqueue the loop to be processed ; Check that when we do unswitching where we re-enqueue the loop to be processed
; again, but manage to delete the loop before ever getting to iterate on it, it ; again, but manage to delete the loop before ever getting to iterate on it, it

View File

@ -1,4 +1,5 @@
; RUN: opt -simple-loop-unswitch -verify-loop-info -verify-dom-info -disable-output < %s ; RUN: opt -simple-loop-unswitch -verify-loop-info -verify-dom-info -disable-output < %s
; RUN: opt -simple-loop-unswitch -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output < %s
; Loop unswitch should be able to unswitch these loops and ; Loop unswitch should be able to unswitch these loops and
; preserve LCSSA and LoopSimplify forms. ; preserve LCSSA and LoopSimplify forms.

View File

@ -1,4 +1,5 @@
; RUN: opt -passes='loop(loop-instsimplify,simplify-cfg,unswitch),verify<loops>' -S < %s | FileCheck %s ; RUN: opt -passes='loop(loop-instsimplify,simplify-cfg,unswitch),verify<loops>' -S < %s | FileCheck %s
; RUN: opt -enable-mssa-loop-dependency=true -verify-memoryssa -passes='loop(loop-instsimplify,simplify-cfg,unswitch),verify<loops>' -S < %s | FileCheck %s
declare void @some_func() noreturn declare void @some_func() noreturn

View File

@ -1,4 +1,5 @@
; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s ; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
; RUN: opt -enable-mssa-loop-dependency=true -verify-memoryssa -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
declare void @some_func() noreturn declare void @some_func() noreturn
declare void @sink(i32) declare void @sink(i32)

View File

@ -1,4 +1,5 @@
; RUN: opt -passes='print<scalar-evolution>,loop(unswitch,loop-instsimplify),print<scalar-evolution>' -enable-nontrivial-unswitch -S < %s 2>%t.scev | FileCheck %s ; RUN: opt -passes='print<scalar-evolution>,loop(unswitch,loop-instsimplify),print<scalar-evolution>' -enable-nontrivial-unswitch -S < %s 2>%t.scev | FileCheck %s
; RUN: opt -enable-mssa-loop-dependency=true -verify-memoryssa -passes='print<scalar-evolution>,loop(unswitch,loop-instsimplify),print<scalar-evolution>' -enable-nontrivial-unswitch -S < %s 2>%t.scev | FileCheck %s
; RUN: FileCheck %s --check-prefix=SCEV < %t.scev ; RUN: FileCheck %s --check-prefix=SCEV < %t.scev
target triple = "x86_64-unknown-linux-gnu" target triple = "x86_64-unknown-linux-gnu"