From dbd67f6f6c4941eb7baec8a06b08788a19e7fb01 Mon Sep 17 00:00:00 2001 From: Michael Zolotukhin Date: Wed, 31 Aug 2016 19:26:19 +0000 Subject: [PATCH] [LoopInfo] Add verification by recomputation. Summary: Current implementation of LI verifier isn't ideal and fails to detect some cases when LI is incorrect. For instance, it checks that all recorded loops are in a correct form, but it has no way to check if there are no more other (unrecorded in LI) loops in the function. This patch adds a way to detect such bugs. Reviewers: chandlerc, sanjoy, hfinkel Subscribers: llvm-commits, silvas, mzolotukhin Differential Revision: https://reviews.llvm.org/D23437 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280280 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/LoopInfo.h | 2 +- include/llvm/Analysis/LoopInfoImpl.h | 65 +++++++++++++++++++++++- lib/Analysis/LoopInfo.cpp | 9 ++-- lib/Transforms/Scalar/LoopDistribute.cpp | 2 +- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h index 651a749a6d6..85c06826dae 100644 --- a/include/llvm/Analysis/LoopInfo.h +++ b/include/llvm/Analysis/LoopInfo.h @@ -635,7 +635,7 @@ public: // Debugging void print(raw_ostream &OS) const; - void verify() const; + void verify(const DominatorTreeBase &DomTree) const; }; // Implementation in LoopInfoImpl.h diff --git a/include/llvm/Analysis/LoopInfoImpl.h b/include/llvm/Analysis/LoopInfoImpl.h index 72a09cdd055..6635860139b 100644 --- a/include/llvm/Analysis/LoopInfoImpl.h +++ b/include/llvm/Analysis/LoopInfoImpl.h @@ -17,6 +17,7 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Dominators.h" @@ -514,8 +515,26 @@ void LoopInfoBase::print(raw_ostream &OS) const { #endif } -template -void LoopInfoBase::verify() const { +template +bool compareVectors(std::vector &BB1, std::vector &BB2) { + std::sort(BB1.begin(), BB1.end()); + std::sort(BB2.begin(), BB2.end()); + return BB1 == BB2; +} + +template +static void +addInnerLoopsToHeadersMap(DenseMap &LoopHeaders, + const LoopInfoBase &LI, + const LoopT &L) { + LoopHeaders[L.getHeader()] = &L; + for (LoopT *SL : L) + addInnerLoopsToHeadersMap(LoopHeaders, LI, *SL); +} + +template +void LoopInfoBase::verify( + const DominatorTreeBase &DomTree) const { DenseSet Loops; for (iterator I = begin(), E = end(); I != E; ++I) { assert(!(*I)->getParentLoop() && "Top-level loop has a parent!"); @@ -530,6 +549,48 @@ void LoopInfoBase::verify() const { assert(Loops.count(L) && "orphaned loop"); assert(L->contains(BB) && "orphaned block"); } + + // Recompute LoopInfo to verify loops structure. + LoopInfoBase OtherLI; + OtherLI.analyze(DomTree); + + DenseMap LoopHeaders1; + DenseMap LoopHeaders2; + + for (LoopT *L : *this) + addInnerLoopsToHeadersMap(LoopHeaders1, *this, *L); + for (LoopT *L : OtherLI) + addInnerLoopsToHeadersMap(LoopHeaders2, OtherLI, *L); + assert(LoopHeaders1.size() == LoopHeaders2.size() && + "LoopInfo is incorrect."); + + auto compareLoops = [&](const LoopT *L1, const LoopT *L2) { + BlockT *H1 = L1->getHeader(); + BlockT *H2 = L2->getHeader(); + if (H1 != H2) + return false; + std::vector BB1 = L1->getBlocks(); + std::vector BB2 = L2->getBlocks(); + if (!compareVectors(BB1, BB2)) + return false; + + std::vector SubLoopHeaders1; + std::vector SubLoopHeaders2; + for (LoopT *L : *L1) + SubLoopHeaders1.push_back(L->getHeader()); + for (LoopT *L : *L2) + SubLoopHeaders2.push_back(L->getHeader()); + + if (!compareVectors(SubLoopHeaders1, SubLoopHeaders2)) + return false; + return true; + }; + + for (auto &I : LoopHeaders1) { + BlockT *H = I.first; + bool LoopsMatch = compareLoops(LoopHeaders1[H], LoopHeaders2[H]); + assert(LoopsMatch && "LoopInfo is incorrect."); + } #endif } diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index 9d2e38e19da..a5f816dd5ad 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -703,8 +703,10 @@ void LoopInfoWrapperPass::verifyAnalysis() const { // -verify-loop-info option can enable this. In order to perform some // checking by default, LoopPass has been taught to call verifyLoop manually // during loop pass sequences. - if (VerifyLoopInfo) - LI.verify(); + if (VerifyLoopInfo) { + auto &DT = getAnalysis().getDomTree(); + LI.verify(DT); + } } void LoopInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { @@ -719,7 +721,8 @@ void LoopInfoWrapperPass::print(raw_ostream &OS, const Module *) const { PreservedAnalyses LoopVerifierPass::run(Function &F, FunctionAnalysisManager &AM) { LoopInfo &LI = AM.getResult(F); - LI.verify(); + auto &DT = AM.getResult(F); + LI.verify(DT); return PreservedAnalyses::all(); } diff --git a/lib/Transforms/Scalar/LoopDistribute.cpp b/lib/Transforms/Scalar/LoopDistribute.cpp index 74cfdbfa84e..ad973cf31de 100644 --- a/lib/Transforms/Scalar/LoopDistribute.cpp +++ b/lib/Transforms/Scalar/LoopDistribute.cpp @@ -742,7 +742,7 @@ public: DEBUG(Partitions.printBlocks()); if (LDistVerify) { - LI->verify(); + LI->verify(*DT); DT->verifyDomTree(); }