[llvm] r314435 - [JumpThreading] Preserve DT and LVI across the pass
Philip Reames via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 29 08:29:11 PDT 2017
Er, have you checked the history here? I thought this preservation was
removed relatively recently to avoid a correctness bug.
Philip
On 09/28/2017 10:24 AM, Evandro Menezes via llvm-commits wrote:
> Author: evandro
> Date: Thu Sep 28 10:24:40 2017
> New Revision: 314435
>
> URL: http://llvm.org/viewvc/llvm-project?rev=314435&view=rev
> Log:
> [JumpThreading] Preserve DT and LVI across the pass
>
> JumpThreading now preserves dominance and lazy value information across the
> entire pass. The pass manager is also informed of this preservation with
> the goal of DT and LVI being recalculated fewer times overall during
> compilation.
>
> This change prepares JumpThreading for enhanced opportunities; particularly
> those across loop boundaries.
>
> Patch by: Brian Rzycki <b.rzycki at samsung.com>,
> Sebastian Pop <s.pop at samsung.com>
>
> Differential revision: https://reviews.llvm.org/D37528
>
> Modified:
> llvm/trunk/include/llvm/Transforms/Scalar/JumpThreading.h
> llvm/trunk/include/llvm/Transforms/Utils/Local.h
> llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
> llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp
> llvm/trunk/lib/Transforms/Utils/Local.cpp
> llvm/trunk/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll
>
> Modified: llvm/trunk/include/llvm/Transforms/Scalar/JumpThreading.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar/JumpThreading.h?rev=314435&r1=314434&r2=314435&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Transforms/Scalar/JumpThreading.h (original)
> +++ llvm/trunk/include/llvm/Transforms/Scalar/JumpThreading.h Thu Sep 28 10:24:40 2017
> @@ -34,6 +34,7 @@ class BinaryOperator;
> class BranchInst;
> class CmpInst;
> class Constant;
> +class DominatorTree;
> class Function;
> class Instruction;
> class IntrinsicInst;
> @@ -77,6 +78,7 @@ class JumpThreadingPass : public PassInf
> TargetLibraryInfo *TLI;
> LazyValueInfo *LVI;
> AliasAnalysis *AA;
> + DominatorTree *DT;
> std::unique_ptr<BlockFrequencyInfo> BFI;
> std::unique_ptr<BranchProbabilityInfo> BPI;
> bool HasProfileData = false;
> @@ -107,7 +109,7 @@ public:
>
> // Glue for old PM.
> bool runImpl(Function &F, TargetLibraryInfo *TLI_, LazyValueInfo *LVI_,
> - AliasAnalysis *AA_, bool HasProfileData_,
> + AliasAnalysis *AA_, DominatorTree *DT_, bool HasProfileData_,
> std::unique_ptr<BlockFrequencyInfo> BFI_,
> std::unique_ptr<BranchProbabilityInfo> BPI_);
>
>
> Modified: llvm/trunk/include/llvm/Transforms/Utils/Local.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/Local.h?rev=314435&r1=314434&r2=314435&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Transforms/Utils/Local.h (original)
> +++ llvm/trunk/include/llvm/Transforms/Utils/Local.h Thu Sep 28 10:24:40 2017
> @@ -79,7 +79,8 @@ struct SimplifyCFGOptions {
> /// conditions and indirectbr addresses this might make dead if
> /// DeleteDeadConditions is true.
> bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions = false,
> - const TargetLibraryInfo *TLI = nullptr);
> + const TargetLibraryInfo *TLI = nullptr,
> + DominatorTree *DT = nullptr);
>
> //===----------------------------------------------------------------------===//
> // Local dead code elimination.
> @@ -133,7 +134,8 @@ bool SimplifyInstructionsInBlock(BasicBl
> ///
> /// .. and delete the predecessor corresponding to the '1', this will attempt to
> /// recursively fold the 'and' to 0.
> -void RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred);
> +void RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
> + DominatorTree *DT = nullptr);
>
> /// BB is a block with one predecessor and its predecessor is known to have one
> /// successor (BB!). Eliminate the edge between them, moving the instructions in
> @@ -144,7 +146,8 @@ void MergeBasicBlockIntoOnlyPred(BasicBl
> /// other than PHI nodes, potential debug intrinsics and the branch. If
> /// possible, eliminate BB by rewriting all the predecessors to branch to the
> /// successor block and return true. If we can't transform, return false.
> -bool TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB);
> +bool TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
> + DominatorTree *DT = nullptr);
>
> /// Check for and eliminate duplicate PHI nodes in this block. This doesn't try
> /// to be clever about PHI nodes which differ only in the order of the incoming
> @@ -342,7 +345,8 @@ unsigned removeAllNonTerminatorAndEHPadI
> /// Insert an unreachable instruction before the specified
> /// instruction, making it and the rest of the code in the block dead.
> unsigned changeToUnreachable(Instruction *I, bool UseLLVMTrap,
> - bool PreserveLCSSA = false);
> + bool PreserveLCSSA = false,
> + DominatorTree *DT = nullptr);
>
> /// Convert the CallInst to InvokeInst with the specified unwind edge basic
> /// block. This also splits the basic block where CI is located, because
> @@ -357,12 +361,13 @@ BasicBlock *changeToInvokeAndSplitBasicB
> ///
> /// \param BB Block whose terminator will be replaced. Its terminator must
> /// have an unwind successor.
> -void removeUnwindEdge(BasicBlock *BB);
> +void removeUnwindEdge(BasicBlock *BB, DominatorTree *DT = nullptr);
>
> /// Remove all blocks that can not be reached from the function's entry.
> ///
> /// Returns true if any basic block was removed.
> -bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr);
> +bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr,
> + DominatorTree *DT = nullptr);
>
> /// Combine the metadata of two instructions so that K can replace J
> ///
>
> Modified: llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp?rev=314435&r1=314434&r2=314435&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp Thu Sep 28 10:24:40 2017
> @@ -55,6 +55,7 @@ namespace {
> bool runOnFunction(Function &F) override;
>
> void getAnalysisUsage(AnalysisUsage &AU) const override {
> + AU.addRequired<DominatorTreeWrapperPass>();
> AU.addRequired<LazyValueInfoWrapperPass>();
> AU.addPreserved<GlobalsAAWrapperPass>();
> }
> @@ -64,6 +65,7 @@ namespace {
> char CorrelatedValuePropagation::ID = 0;
> INITIALIZE_PASS_BEGIN(CorrelatedValuePropagation, "correlated-propagation",
> "Value Propagation", false, false)
> +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
> INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass)
> INITIALIZE_PASS_END(CorrelatedValuePropagation, "correlated-propagation",
> "Value Propagation", false, false)
>
> Modified: llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp?rev=314435&r1=314434&r2=314435&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp Thu Sep 28 10:24:40 2017
> @@ -131,10 +131,11 @@ namespace {
> bool runOnFunction(Function &F) override;
>
> void getAnalysisUsage(AnalysisUsage &AU) const override {
> - if (PrintLVIAfterJumpThreading)
> - AU.addRequired<DominatorTreeWrapperPass>();
> + AU.addRequired<DominatorTreeWrapperPass>();
> + AU.addPreserved<DominatorTreeWrapperPass>();
> AU.addRequired<AAResultsWrapperPass>();
> AU.addRequired<LazyValueInfoWrapperPass>();
> + AU.addPreserved<LazyValueInfoWrapperPass>();
> AU.addPreserved<GlobalsAAWrapperPass>();
> AU.addRequired<TargetLibraryInfoWrapperPass>();
> }
> @@ -148,6 +149,7 @@ char JumpThreading::ID = 0;
>
> INITIALIZE_PASS_BEGIN(JumpThreading, "jump-threading",
> "Jump Threading", false, false)
> +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
> INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass)
> INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
> INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
> @@ -277,6 +279,9 @@ bool JumpThreading::runOnFunction(Functi
> if (skipFunction(F))
> return false;
> auto TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
> + // Get DT analysis before LVI. When LVI is initialized it conditionally adds
> + // DT if it's available.
> + auto DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
> auto LVI = &getAnalysis<LazyValueInfoWrapperPass>().getLVI();
> auto AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
> std::unique_ptr<BlockFrequencyInfo> BFI;
> @@ -288,12 +293,11 @@ bool JumpThreading::runOnFunction(Functi
> BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
> }
>
> - bool Changed = Impl.runImpl(F, TLI, LVI, AA, HasProfileData, std::move(BFI),
> - std::move(BPI));
> + bool Changed = Impl.runImpl(F, TLI, LVI, AA, DT, HasProfileData,
> + std::move(BFI), std::move(BPI));
> if (PrintLVIAfterJumpThreading) {
> dbgs() << "LVI for function '" << F.getName() << "':\n";
> - LVI->printLVI(F, getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
> - dbgs());
> + LVI->printLVI(F, *DT, dbgs());
> }
> return Changed;
> }
> @@ -301,6 +305,9 @@ bool JumpThreading::runOnFunction(Functi
> PreservedAnalyses JumpThreadingPass::run(Function &F,
> FunctionAnalysisManager &AM) {
> auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
> + // Get DT analysis before LVI. When LVI is initialized it conditionally adds
> + // DT if it's available.
> + auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
> auto &LVI = AM.getResult<LazyValueAnalysis>(F);
> auto &AA = AM.getResult<AAManager>(F);
>
> @@ -313,25 +320,28 @@ PreservedAnalyses JumpThreadingPass::run
> BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
> }
>
> - bool Changed = runImpl(F, &TLI, &LVI, &AA, HasProfileData, std::move(BFI),
> - std::move(BPI));
> + bool Changed = runImpl(F, &TLI, &LVI, &AA, &DT, HasProfileData,
> + std::move(BFI), std::move(BPI));
>
> if (!Changed)
> return PreservedAnalyses::all();
> PreservedAnalyses PA;
> PA.preserve<GlobalsAA>();
> + PA.preserve<DominatorTreeAnalysis>();
> + PA.preserve<LazyValueAnalysis>();
> return PA;
> }
>
> bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
> LazyValueInfo *LVI_, AliasAnalysis *AA_,
> - bool HasProfileData_,
> + DominatorTree *DT_, bool HasProfileData_,
> std::unique_ptr<BlockFrequencyInfo> BFI_,
> std::unique_ptr<BranchProbabilityInfo> BPI_) {
> DEBUG(dbgs() << "Jump threading on function '" << F.getName() << "'\n");
> TLI = TLI_;
> LVI = LVI_;
> AA = AA_;
> + DT = DT_;
> BFI.reset();
> BPI.reset();
> // When profile data is available, we need to update edge weights after
> @@ -353,8 +363,7 @@ bool JumpThreadingPass::runImpl(Function
> // back edges. This works for normal cases but not for unreachable blocks as
> // they may have cycle with no back edge.
> bool EverChanged = false;
> - EverChanged |= removeUnreachableBlocks(F, LVI);
> -
> + EverChanged |= removeUnreachableBlocks(F, LVI, DT);
> FindLoopHeaders(F);
>
> bool Changed;
> @@ -400,7 +409,7 @@ bool JumpThreadingPass::runImpl(Function
> // awesome, but it allows us to use AssertingVH to prevent nasty
> // dangling pointer issues within LazyValueInfo.
> LVI->eraseBlock(BB);
> - if (TryToSimplifyUncondBranchFromEmptyBlock(BB))
> + if (TryToSimplifyUncondBranchFromEmptyBlock(BB, DT))
> Changed = true;
> }
> }
> @@ -948,7 +957,7 @@ bool JumpThreadingPass::ProcessBlock(Bas
> LoopHeaders.insert(BB);
>
> LVI->eraseBlock(SinglePred);
> - MergeBasicBlockIntoOnlyPred(BB);
> + MergeBasicBlockIntoOnlyPred(BB, DT);
>
> // Now that BB is merged into SinglePred (i.e. SinglePred Code followed by
> // BB code within one basic block `BB`), we need to invalidate the LVI
> @@ -1031,18 +1040,27 @@ bool JumpThreadingPass::ProcessBlock(Bas
> // successors to branch to. Let GetBestDestForJumpOnUndef decide.
> if (isa<UndefValue>(Condition)) {
> unsigned BestSucc = GetBestDestForJumpOnUndef(BB);
> + std::vector<DominatorTree::UpdateType> Updates;
>
> // Fold the branch/switch.
> TerminatorInst *BBTerm = BB->getTerminator();
> for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) {
> if (i == BestSucc) continue;
> - BBTerm->getSuccessor(i)->removePredecessor(BB, true);
> + BasicBlock *Succ = BBTerm->getSuccessor(i);
> + Succ->removePredecessor(BB, true);
> + if (Succ == BB)
> + continue;
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, BB, Succ};
> + // Make sure to remove a DT edge exactly once and not an edge to itself.
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end())
> + Updates.push_back(UT);
> }
>
> DEBUG(dbgs() << " In block '" << BB->getName()
> << "' folding undef terminator: " << *BBTerm << '\n');
> BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm);
> BBTerm->eraseFromParent();
> + DT->applyUpdates(Updates);
> return true;
> }
>
> @@ -1053,7 +1071,7 @@ bool JumpThreadingPass::ProcessBlock(Bas
> DEBUG(dbgs() << " In block '" << BB->getName()
> << "' folding terminator: " << *BB->getTerminator() << '\n');
> ++NumFolds;
> - ConstantFoldTerminator(BB, true);
> + ConstantFoldTerminator(BB, true, nullptr, DT);
> return true;
> }
>
> @@ -1086,9 +1104,12 @@ bool JumpThreadingPass::ProcessBlock(Bas
> if (Ret != LazyValueInfo::Unknown) {
> unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0;
> unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1;
> - CondBr->getSuccessor(ToRemove)->removePredecessor(BB, true);
> + BasicBlock *ToRemoveSucc = CondBr->getSuccessor(ToRemove);
> + ToRemoveSucc->removePredecessor(BB, true);
> BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr);
> CondBr->eraseFromParent();
> + if (BB != ToRemoveSucc)
> + DT->deleteEdge(BB, ToRemoveSucc);
> if (CondCmp->use_empty())
> CondCmp->eraseFromParent();
> // We can safely replace *some* uses of the CondInst if it has
> @@ -1182,9 +1203,12 @@ bool JumpThreadingPass::ProcessImpliedCo
> Optional<bool> Implication =
> isImpliedCondition(PBI->getCondition(), Cond, DL, CondIsTrue);
> if (Implication) {
> - BI->getSuccessor(*Implication ? 1 : 0)->removePredecessor(BB);
> + BasicBlock *RemoveSucc = BI->getSuccessor(*Implication ? 1 : 0);
> + RemoveSucc->removePredecessor(BB);
> BranchInst::Create(BI->getSuccessor(*Implication ? 0 : 1), BI);
> BI->eraseFromParent();
> + if (BB != RemoveSucc)
> + DT->deleteEdge(BB, RemoveSucc);
> return true;
> }
> CurrentBB = CurrentPred;
> @@ -1576,18 +1600,27 @@ bool JumpThreadingPass::ProcessThreadabl
> if (OnlyDest && OnlyDest != MultipleDestSentinel) {
> if (PredWithKnownDest ==
> (size_t)std::distance(pred_begin(BB), pred_end(BB))) {
> + std::vector<DominatorTree::UpdateType> Updates;
> bool SeenFirstBranchToOnlyDest = false;
> for (BasicBlock *SuccBB : successors(BB)) {
> - if (SuccBB == OnlyDest && !SeenFirstBranchToOnlyDest)
> + if (SuccBB == OnlyDest && !SeenFirstBranchToOnlyDest) {
> SeenFirstBranchToOnlyDest = true; // Don't modify the first branch.
> - else
> + } else {
> SuccBB->removePredecessor(BB, true); // This is unreachable successor.
> + if (SuccBB != OnlyDest && SuccBB != BB) {
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, BB, SuccBB};
> + // Make sure to remove a DT edge exactly once.
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end())
> + Updates.push_back(UT);
> + }
> + }
> }
>
> // Finally update the terminator.
> TerminatorInst *Term = BB->getTerminator();
> BranchInst::Create(OnlyDest, Term);
> Term->eraseFromParent();
> + DT->applyUpdates(Updates);
>
> // If the condition is now dead due to the removal of the old terminator,
> // erase it.
> @@ -1922,7 +1955,6 @@ bool JumpThreadingPass::ThreadEdge(Basic
>
> UsesToRename.push_back(&U);
> }
> -
> // If there are no uses outside the block, we're done with this instruction.
> if (UsesToRename.empty())
> continue;
> @@ -1951,6 +1983,10 @@ bool JumpThreadingPass::ThreadEdge(Basic
> PredTerm->setSuccessor(i, NewBB);
> }
>
> + DT->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB},
> + {DominatorTree::Insert, PredBB, NewBB},
> + {DominatorTree::Delete, PredBB, BB}});
> +
> // At this point, the IR is fully up to date and consistent. Do a quick scan
> // over the new instructions and zap any that are constants or dead. This
> // frequently happens because of phi translation.
> @@ -1977,7 +2013,7 @@ BasicBlock *JumpThreadingPass::SplitBloc
> for (auto Pred : Preds)
> PredBBFreq += BFI->getBlockFreq(Pred) * BPI->getEdgeProbability(Pred, BB);
>
> - BasicBlock *PredBB = SplitBlockPredecessors(BB, Preds, Suffix);
> + BasicBlock *PredBB = SplitBlockPredecessors(BB, Preds, Suffix, DT);
>
> // Set the block frequency of the newly created PredBB, which is the sum of
> // frequencies of Preds.
> @@ -2147,7 +2183,7 @@ bool JumpThreadingPass::DuplicateCondBra
> BranchInst *OldPredBranch = dyn_cast<BranchInst>(PredBB->getTerminator());
>
> if (!OldPredBranch || !OldPredBranch->isUnconditional()) {
> - PredBB = SplitEdge(PredBB, BB);
> + PredBB = SplitEdge(PredBB, BB, DT);
> OldPredBranch = cast<BranchInst>(PredBB->getTerminator());
> }
>
> @@ -2244,6 +2280,8 @@ bool JumpThreadingPass::DuplicateCondBra
>
> // Remove the unconditional branch at the end of the PredBB block.
> OldPredBranch->eraseFromParent();
> + if (BB != PredBB)
> + DT->deleteEdge(PredBB, BB);
>
> ++NumDupes;
> return true;
> @@ -2309,6 +2347,7 @@ bool JumpThreadingPass::TryToUnfoldSelec
> // Move the unconditional branch to NewBB.
> PredTerm->removeFromParent();
> NewBB->getInstList().insert(NewBB->end(), PredTerm);
> + DT->insertEdge(NewBB, BB);
> // Create a conditional branch and update PHI nodes.
> BranchInst::Create(NewBB, BB, SI->getCondition(), Pred);
> CondLHS->setIncomingValue(I, SI->getFalseValue());
> @@ -2316,6 +2355,7 @@ bool JumpThreadingPass::TryToUnfoldSelec
> // The select is now dead.
> SI->eraseFromParent();
>
> + DT->insertEdge(Pred, NewBB);
> // Update any other PHI nodes in BB.
> for (BasicBlock::iterator BI = BB->begin();
> PHINode *Phi = dyn_cast<PHINode>(BI); ++BI)
> @@ -2393,7 +2433,7 @@ bool JumpThreadingPass::TryToUnfoldSelec
> continue;
> // Expand the select.
> TerminatorInst *Term =
> - SplitBlockAndInsertIfThen(SI->getCondition(), SI, false);
> + SplitBlockAndInsertIfThen(SI->getCondition(), SI, false, nullptr, DT);
> PHINode *NewPN = PHINode::Create(SI->getType(), 2, "", SI);
> NewPN->addIncoming(SI->getTrueValue(), Term->getParent());
> NewPN->addIncoming(SI->getFalseValue(), BB);
> @@ -2485,8 +2525,8 @@ bool JumpThreadingPass::ThreadGuard(Basi
> if (!TrueDestIsSafe && !FalseDestIsSafe)
> return false;
>
> - BasicBlock *UnguardedBlock = TrueDestIsSafe ? TrueDest : FalseDest;
> - BasicBlock *GuardedBlock = FalseDestIsSafe ? TrueDest : FalseDest;
> + BasicBlock *PredUnguardedBlock = TrueDestIsSafe ? TrueDest : FalseDest;
> + BasicBlock *PredGuardedBlock = FalseDestIsSafe ? TrueDest : FalseDest;
>
> ValueToValueMapTy UnguardedMapping, GuardedMapping;
> Instruction *AfterGuard = Guard->getNextNode();
> @@ -2495,17 +2535,28 @@ bool JumpThreadingPass::ThreadGuard(Basi
> return false;
> // Duplicate all instructions before the guard and the guard itself to the
> // branch where implication is not proved.
> - GuardedBlock = DuplicateInstructionsInSplitBetween(
> - BB, GuardedBlock, AfterGuard, GuardedMapping);
> + BasicBlock *GuardedBlock = DuplicateInstructionsInSplitBetween(
> + BB, PredGuardedBlock, AfterGuard, GuardedMapping);
> assert(GuardedBlock && "Could not create the guarded block?");
> // Duplicate all instructions before the guard in the unguarded branch.
> // Since we have successfully duplicated the guarded block and this block
> // has fewer instructions, we expect it to succeed.
> - UnguardedBlock = DuplicateInstructionsInSplitBetween(BB, UnguardedBlock,
> - Guard, UnguardedMapping);
> + BasicBlock *UnguardedBlock = DuplicateInstructionsInSplitBetween(
> + BB, PredUnguardedBlock, Guard, UnguardedMapping);
> assert(UnguardedBlock && "Could not create the unguarded block?");
> DEBUG(dbgs() << "Moved guard " << *Guard << " to block "
> << GuardedBlock->getName() << "\n");
> + // DuplicateInstructionsInSplitBetween inserts a new block, BB.split, between
> + // PredBB and BB. We need to perform two inserts and one delete in DT for each
> + // of the above calls.
> + DT->applyUpdates({// Guarded block split.
> + {DominatorTree::Delete, PredGuardedBlock, BB},
> + {DominatorTree::Insert, PredGuardedBlock, GuardedBlock},
> + {DominatorTree::Insert, GuardedBlock, BB},
> + // Unguarded block split.
> + {DominatorTree::Delete, PredUnguardedBlock, BB},
> + {DominatorTree::Insert, PredUnguardedBlock, UnguardedBlock},
> + {DominatorTree::Insert, UnguardedBlock, BB}});
>
> // Some instructions before the guard may still have uses. For them, we need
> // to create Phi nodes merging their copies in both guarded and unguarded
>
> Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=314435&r1=314434&r2=314435&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
> +++ llvm/trunk/lib/Transforms/Utils/Local.cpp Thu Sep 28 10:24:40 2017
> @@ -68,7 +68,8 @@ STATISTIC(NumRemoved, "Number of unreach
> /// conditions and indirectbr addresses this might make dead if
> /// DeleteDeadConditions is true.
> bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
> - const TargetLibraryInfo *TLI) {
> + const TargetLibraryInfo *TLI,
> + DominatorTree *DT) {
> TerminatorInst *T = BB->getTerminator();
> IRBuilder<> Builder(T);
>
> @@ -95,6 +96,8 @@ bool llvm::ConstantFoldTerminator(BasicB
> // Replace the conditional branch with an unconditional one.
> Builder.CreateBr(Destination);
> BI->eraseFromParent();
> + if (DT && OldDest != Destination && OldDest != BB)
> + DT->deleteEdge(BB, OldDest);
> return true;
> }
>
> @@ -165,9 +168,17 @@ bool llvm::ConstantFoldTerminator(BasicB
> createBranchWeights(Weights));
> }
> // Remove this entry.
> - DefaultDest->removePredecessor(SI->getParent());
> + BasicBlock *ParentBB = SI->getParent();
> + DefaultDest->removePredecessor(ParentBB);
> i = SI->removeCase(i);
> e = SI->case_end();
> + if (DT && DefaultDest != ParentBB) {
> + // DefaultDest may still be a successor of a non-default case.
> + if (none_of(successors(ParentBB), [DefaultDest](BasicBlock *S) {
> + return S == DefaultDest;
> + }))
> + DT->deleteEdge(ParentBB, DefaultDest);
> + }
> continue;
> }
>
> @@ -193,19 +204,29 @@ bool llvm::ConstantFoldTerminator(BasicB
> // Insert the new branch.
> Builder.CreateBr(TheOnlyDest);
> BasicBlock *BB = SI->getParent();
> + BasicBlock *TheOnlyDestCheck = TheOnlyDest;
> + std::vector<DominatorTree::UpdateType> Updates;
>
> // Remove entries from PHI nodes which we no longer branch to...
> for (BasicBlock *Succ : SI->successors()) {
> // Found case matching a constant operand?
> - if (Succ == TheOnlyDest)
> + if (Succ == TheOnlyDest) {
> TheOnlyDest = nullptr; // Don't modify the first branch to TheOnlyDest
> - else
> + } else {
> Succ->removePredecessor(BB);
> + if (DT && Succ != TheOnlyDestCheck && Succ != BB) {
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, BB, Succ};
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end())
> + Updates.push_back(UT);
> + }
> + }
> }
>
> // Delete the old switch.
> Value *Cond = SI->getCondition();
> SI->eraseFromParent();
> + if (DT && !Updates.empty())
> + DT->applyUpdates(Updates);
> if (DeleteDeadConditions)
> RecursivelyDeleteTriviallyDeadInstructions(Cond, TLI);
> return true;
> @@ -253,17 +274,30 @@ bool llvm::ConstantFoldTerminator(BasicB
> if (BlockAddress *BA =
> dyn_cast<BlockAddress>(IBI->getAddress()->stripPointerCasts())) {
> BasicBlock *TheOnlyDest = BA->getBasicBlock();
> + BasicBlock *TheOnlyDestCheck = TheOnlyDest;
> + std::vector<DominatorTree::UpdateType> Updates;
> // Insert the new branch.
> Builder.CreateBr(TheOnlyDest);
>
> for (unsigned i = 0, e = IBI->getNumDestinations(); i != e; ++i) {
> - if (IBI->getDestination(i) == TheOnlyDest)
> + if (IBI->getDestination(i) == TheOnlyDest) {
> TheOnlyDest = nullptr;
> - else
> - IBI->getDestination(i)->removePredecessor(IBI->getParent());
> + } else {
> + BasicBlock *ParentBB = IBI->getParent();
> + BasicBlock *DestBB = IBI->getDestination(i);
> + DestBB->removePredecessor(ParentBB);
> + if (DT && DestBB != TheOnlyDestCheck && DestBB != ParentBB) {
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, ParentBB,
> + DestBB};
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end())
> + Updates.push_back(UT);
> + }
> + }
> }
> Value *Address = IBI->getAddress();
> IBI->eraseFromParent();
> + if (DT && !Updates.empty())
> + DT->applyUpdates(Updates);
> if (DeleteDeadConditions)
> RecursivelyDeleteTriviallyDeadInstructions(Address, TLI);
>
> @@ -553,7 +587,8 @@ bool llvm::SimplifyInstructionsInBlock(B
> ///
> /// .. and delete the predecessor corresponding to the '1', this will attempt to
> /// recursively fold the and to 0.
> -void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred) {
> +void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
> + DominatorTree *DT) {
> // This only adjusts blocks with PHI nodes.
> if (!isa<PHINode>(BB->begin()))
> return;
> @@ -576,6 +611,8 @@ void llvm::RemovePredecessorAndSimplify(
> // of the block.
> if (PhiIt != OldPhiIt) PhiIt = &BB->front();
> }
> + if (DT && BB != Pred)
> + DT->deleteEdge(Pred, BB);
> }
>
>
> @@ -597,6 +634,23 @@ void llvm::MergeBasicBlockIntoOnlyPred(B
> BasicBlock *PredBB = DestBB->getSinglePredecessor();
> assert(PredBB && "Block doesn't have a single predecessor!");
>
> + // Collect all the edges that enter PredBB, discarding edges to itself and
> + // duplicates. These dominator edges will be redirected to DestBB.
> + std::vector<DominatorTree::UpdateType> Updates;
> + if (DT)
> + for (pred_iterator PI = pred_begin(PredBB), E = pred_end(PredBB); PI != E;
> + ++PI) {
> + if (*PI == PredBB)
> + continue;
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, *PI, PredBB};
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end()) {
> + Updates.push_back(UT);
> + // DestBB cannot dominate itself.
> + if (*PI != DestBB)
> + Updates.push_back({DominatorTree::Insert, *PI, DestBB});
> + }
> + }
> +
> // Zap anything that took the address of DestBB. Not doing this will give the
> // address an invalid value.
> if (DestBB->hasAddressTaken()) {
> @@ -617,16 +671,25 @@ void llvm::MergeBasicBlockIntoOnlyPred(B
>
> // If the PredBB is the entry block of the function, move DestBB up to
> // become the entry block after we erase PredBB.
> - if (PredBB == &DestBB->getParent()->getEntryBlock())
> + bool ReplacedEntryBB = false;
> + if (PredBB == &DestBB->getParent()->getEntryBlock()) {
> DestBB->moveAfter(PredBB);
> + ReplacedEntryBB = true;
> + }
>
> - if (DT) {
> - BasicBlock *PredBBIDom = DT->getNode(PredBB)->getIDom()->getBlock();
> - DT->changeImmediateDominator(DestBB, PredBBIDom);
> - DT->eraseNode(PredBB);
> + if (DT && !ReplacedEntryBB) {
> + Updates.push_back({DominatorTree::Delete, PredBB, DestBB});
> + DT->applyUpdates(Updates);
> }
> +
> // Nuke BB.
> PredBB->eraseFromParent();
> +
> + // The entry block was removed and there is no external interface for the
> + // dominator tree to be notified of this change. In this corner-case we
> + // recalculate the entire tree.
> + if (DT && ReplacedEntryBB)
> + DT->recalculate(*(DestBB->getParent()));
> }
>
> /// CanMergeValues - Return true if we can choose one of these values to use
> @@ -834,7 +897,8 @@ static void redirectValuesFromPredecesso
> /// potential side-effect free intrinsics and the branch. If possible,
> /// eliminate BB by rewriting all the predecessors to branch to the successor
> /// block and return true. If we can't transform, return false.
> -bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) {
> +bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
> + DominatorTree *DT) {
> assert(BB != &BB->getParent()->getEntryBlock() &&
> "TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
>
> @@ -875,6 +939,20 @@ bool llvm::TryToSimplifyUncondBranchFrom
>
> DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
>
> + // Collect all the edges that enter BB, discarding edges to itself and
> + // duplicates. These dominator edges will be redirected to Succ.
> + std::vector<DominatorTree::UpdateType> Updates;
> + if (DT)
> + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) {
> + if (*PI == BB)
> + continue;
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, *PI, BB};
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end()) {
> + Updates.push_back(UT);
> + Updates.push_back({DominatorTree::Insert, *PI, Succ});
> + }
> + }
> +
> if (isa<PHINode>(Succ->begin())) {
> // If there is more than one pred of succ, and there are PHI nodes in
> // the successor, then we need to add incoming edges for the PHI nodes
> @@ -909,16 +987,27 @@ bool llvm::TryToSimplifyUncondBranchFrom
> // add the metadata to the branch instructions in the predecessors.
> unsigned LoopMDKind = BB->getContext().getMDKindID("llvm.loop");
> Instruction *TI = BB->getTerminator();
> - if (TI)
> + if (TI) {
> if (MDNode *LoopMD = TI->getMetadata(LoopMDKind))
> for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) {
> BasicBlock *Pred = *PI;
> Pred->getTerminator()->setMetadata(LoopMDKind, LoopMD);
> }
> + // Replace the terminator instruction with unreachable to ensure the CFG is
> + // consistent. This is necessary for dominance to be correctly calculated.
> + new UnreachableInst(BB->getContext(), TI);
> + TI->eraseFromParent();
> + }
>
> // Everything that jumped to BB now goes to Succ.
> BB->replaceAllUsesWith(Succ);
> if (!Succ->hasName()) Succ->takeName(BB);
> +
> + if (DT) {
> + Updates.push_back({DominatorTree::Delete, BB, Succ});
> + DT->applyUpdates(Updates);
> + }
> +
> BB->eraseFromParent(); // Delete the old basic block.
> return true;
> }
> @@ -1399,13 +1488,19 @@ unsigned llvm::removeAllNonTerminatorAnd
> }
>
> unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap,
> - bool PreserveLCSSA) {
> + bool PreserveLCSSA, DominatorTree *DT) {
> BasicBlock *BB = I->getParent();
> + std::vector<DominatorTree::UpdateType> Updates;
> // Loop over all of the successors, removing BB's entry from any PHI
> // nodes.
> - for (BasicBlock *Successor : successors(BB))
> + for (BasicBlock *Successor : successors(BB)) {
> Successor->removePredecessor(BB, PreserveLCSSA);
> -
> + if (DT && BB != Successor) {
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, BB, Successor};
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end())
> + Updates.push_back(UT);
> + }
> + }
> // Insert a call to llvm.trap right before this. This turns the undefined
> // behavior into a hard fail instead of falling through into random code.
> if (UseLLVMTrap) {
> @@ -1425,11 +1520,13 @@ unsigned llvm::changeToUnreachable(Instr
> BB->getInstList().erase(BBI++);
> ++NumInstrsRemoved;
> }
> + if (DT && !Updates.empty())
> + DT->applyUpdates(Updates);
> return NumInstrsRemoved;
> }
>
> /// changeToCall - Convert the specified invoke into a normal call.
> -static void changeToCall(InvokeInst *II) {
> +static void changeToCall(InvokeInst *II, DominatorTree *DT = nullptr) {
> SmallVector<Value*, 8> Args(II->arg_begin(), II->arg_end());
> SmallVector<OperandBundleDef, 1> OpBundles;
> II->getOperandBundlesAsDefs(OpBundles);
> @@ -1442,11 +1539,16 @@ static void changeToCall(InvokeInst *II)
> II->replaceAllUsesWith(NewCall);
>
> // Follow the call by a branch to the normal destination.
> - BranchInst::Create(II->getNormalDest(), II);
> + BasicBlock *NormalDestBB = II->getNormalDest();
> + BranchInst::Create(NormalDestBB, II);
>
> // Update PHI nodes in the unwind destination
> - II->getUnwindDest()->removePredecessor(II->getParent());
> + BasicBlock *BB = II->getParent();
> + BasicBlock *UnwindDestBB = II->getUnwindDest();
> + UnwindDestBB->removePredecessor(BB);
> II->eraseFromParent();
> + if (DT && BB != UnwindDestBB && NormalDestBB != UnwindDestBB)
> + DT->deleteEdge(BB, UnwindDestBB);
> }
>
> BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI,
> @@ -1487,7 +1589,8 @@ BasicBlock *llvm::changeToInvokeAndSplit
> }
>
> static bool markAliveBlocks(Function &F,
> - SmallPtrSetImpl<BasicBlock*> &Reachable) {
> + SmallPtrSetImpl<BasicBlock *> &Reachable,
> + DominatorTree *DT = nullptr) {
>
> SmallVector<BasicBlock*, 128> Worklist;
> BasicBlock *BB = &F.front();
> @@ -1508,7 +1611,7 @@ static bool markAliveBlocks(Function &F,
> if (II->getIntrinsicID() == Intrinsic::assume) {
> if (match(II->getArgOperand(0), m_CombineOr(m_Zero(), m_Undef()))) {
> // Don't insert a call to llvm.trap right before the unreachable.
> - changeToUnreachable(II, false);
> + changeToUnreachable(II, false, false, DT);
> Changed = true;
> break;
> }
> @@ -1525,7 +1628,8 @@ static bool markAliveBlocks(Function &F,
> // still be useful for widening.
> if (match(II->getArgOperand(0), m_Zero()))
> if (!isa<UnreachableInst>(II->getNextNode())) {
> - changeToUnreachable(II->getNextNode(), /*UseLLVMTrap=*/ false);
> + changeToUnreachable(II->getNextNode(), /*UseLLVMTrap=*/false,
> + false, DT);
> Changed = true;
> break;
> }
> @@ -1535,7 +1639,7 @@ static bool markAliveBlocks(Function &F,
> if (auto *CI = dyn_cast<CallInst>(&I)) {
> Value *Callee = CI->getCalledValue();
> if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
> - changeToUnreachable(CI, /*UseLLVMTrap=*/false);
> + changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DT);
> Changed = true;
> break;
> }
> @@ -1545,7 +1649,7 @@ static bool markAliveBlocks(Function &F,
> // though.
> if (!isa<UnreachableInst>(CI->getNextNode())) {
> // Don't insert a call to llvm.trap right before the unreachable.
> - changeToUnreachable(CI->getNextNode(), false);
> + changeToUnreachable(CI->getNextNode(), false, false, DT);
> Changed = true;
> }
> break;
> @@ -1564,7 +1668,7 @@ static bool markAliveBlocks(Function &F,
> if (isa<UndefValue>(Ptr) ||
> (isa<ConstantPointerNull>(Ptr) &&
> SI->getPointerAddressSpace() == 0)) {
> - changeToUnreachable(SI, true);
> + changeToUnreachable(SI, true, false, DT);
> Changed = true;
> break;
> }
> @@ -1576,16 +1680,19 @@ static bool markAliveBlocks(Function &F,
> // Turn invokes that call 'nounwind' functions into ordinary calls.
> Value *Callee = II->getCalledValue();
> if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
> - changeToUnreachable(II, true);
> + changeToUnreachable(II, true, false, DT);
> Changed = true;
> } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) {
> if (II->use_empty() && II->onlyReadsMemory()) {
> // jump to the normal destination branch.
> + BasicBlock *UnwindDestBB = II->getUnwindDest();
> BranchInst::Create(II->getNormalDest(), II);
> - II->getUnwindDest()->removePredecessor(II->getParent());
> + UnwindDestBB->removePredecessor(II->getParent());
> II->eraseFromParent();
> + if (DT && BB != UnwindDestBB)
> + DT->deleteEdge(BB, UnwindDestBB);
> } else
> - changeToCall(II);
> + changeToCall(II, DT);
> Changed = true;
> }
> } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Terminator)) {
> @@ -1628,7 +1735,7 @@ static bool markAliveBlocks(Function &F,
> }
> }
>
> - Changed |= ConstantFoldTerminator(BB, true);
> + Changed |= ConstantFoldTerminator(BB, true, nullptr, DT);
> for (BasicBlock *Successor : successors(BB))
> if (Reachable.insert(Successor).second)
> Worklist.push_back(Successor);
> @@ -1636,11 +1743,11 @@ static bool markAliveBlocks(Function &F,
> return Changed;
> }
>
> -void llvm::removeUnwindEdge(BasicBlock *BB) {
> +void llvm::removeUnwindEdge(BasicBlock *BB, DominatorTree *DT) {
> TerminatorInst *TI = BB->getTerminator();
>
> if (auto *II = dyn_cast<InvokeInst>(TI)) {
> - changeToCall(II);
> + changeToCall(II, DT);
> return;
> }
>
> @@ -1668,15 +1775,19 @@ void llvm::removeUnwindEdge(BasicBlock *
> UnwindDest->removePredecessor(BB);
> TI->replaceAllUsesWith(NewTI);
> TI->eraseFromParent();
> + if (DT && BB != UnwindDest)
> + DT->deleteEdge(BB, UnwindDest);
> }
>
> /// removeUnreachableBlocks - Remove blocks that are not reachable, even
> /// if they are in a dead cycle. Return true if a change was made, false
> /// otherwise. If `LVI` is passed, this function preserves LazyValueInfo
> /// after modifying the CFG.
> -bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI) {
> +bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
> + DominatorTree *DT) {
> SmallPtrSet<BasicBlock*, 16> Reachable;
> - bool Changed = markAliveBlocks(F, Reachable);
> + bool Changed = markAliveBlocks(F, Reachable, DT);
> + std::vector<DominatorTree::UpdateType> Updates;
>
> // If there are unreachable blocks in the CFG...
> if (Reachable.size() == F.size())
> @@ -1685,6 +1796,8 @@ bool llvm::removeUnreachableBlocks(Funct
> assert(Reachable.size() < F.size());
> NumRemoved += F.size()-Reachable.size();
>
> + SmallPtrSet<TerminatorInst *, 4> TIRemoved;
> +
> // Loop over all of the basic blocks that are not reachable, dropping all of
> // their internal references...
> for (Function::iterator BB = ++F.begin(), E = F.end(); BB != E; ++BB) {
> @@ -1692,13 +1805,35 @@ bool llvm::removeUnreachableBlocks(Funct
> continue;
>
> for (BasicBlock *Successor : successors(&*BB))
> - if (Reachable.count(Successor))
> + if (Reachable.count(Successor)) {
> Successor->removePredecessor(&*BB);
> + if (DT && &*BB != Successor) {
> + DominatorTree::UpdateType UT = {DominatorTree::Delete, &*BB,
> + Successor};
> + if (std::find(Updates.begin(), Updates.end(), UT) == Updates.end())
> + Updates.push_back(UT);
> + }
> + }
> +
> if (LVI)
> LVI->eraseBlock(&*BB);
> +
> + TerminatorInst *TI = BB->getTerminator();
> + TIRemoved.insert(TI);
> + new UnreachableInst(BB->getContext(), TI);
> +
> BB->dropAllReferences();
> }
>
> + // Remove all the terminator instructions after dropping all references. This
> + // keeps the state of the CFG consistent and prevents asserts from circular
> + // use counts in groups of unreachable basic blocks.
> + for (TerminatorInst *TI : TIRemoved)
> + TI->eraseFromParent();
> +
> + if (DT && !Updates.empty())
> + DT->applyUpdates(Updates);
> +
> for (Function::iterator I = ++F.begin(); I != F.end();)
> if (!Reachable.count(&*I))
> I = F.getBasicBlockList().erase(I);
>
> Modified: llvm/trunk/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll?rev=314435&r1=314434&r2=314435&view=diff
> ==============================================================================
> --- llvm/trunk/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll (original)
> +++ llvm/trunk/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll Thu Sep 28 10:24:40 2017
> @@ -19,10 +19,13 @@ entry:
> ; CHECK-NEXT: ; LatticeVal for: 'i32 %a' is: overdefined
> ; CHECK-NEXT: ; LatticeVal for: 'i32 %length' is: overdefined
> ; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%backedge' is: constantrange<0, 400>
> +; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%exit' is: constantrange<399, 400>
> ; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
> ; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%backedge' is: constantrange<1, 401>
> +; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%exit' is: constantrange<400, 401>
> ; CHECK-NEXT: %iv.next = add nsw i32 %iv, 1
> ; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%backedge' is: overdefined
> +; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%exit' is: constantrange<0, -1>
> ; CHECK-NEXT: %cont = icmp slt i32 %iv.next, 400
> ; CHECK-NOT: loop
> loop:
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list