Successfully identified regression in *llvm* in CI configuration tcwg_bmk_llvm_tk1/llvm-release-arm-spec2k6-Os. So far, this commit has regressed CI configurations: - tcwg_bmk_llvm_tk1/llvm-release-arm-spec2k6-Os
Culprit: <cut> commit 3a2b05f9fe74fcf9560632cf2695058d47d8683b Author: Evgeniy Brevnov ybrevnov@azul.com Date: Fri Jul 24 18:57:10 2020 +0700
[BPI][NFC] Consolidate code to deal with SCCs under a dedicated data structure.
In order to facilitate review of D79485 here is a small NFC change which restructures code around handling of SCCs in BPI.
Reviewed By: davidxl
Differential Revision: https://reviews.llvm.org/D84514 </cut>
Results regressed to (for first_bad == 3a2b05f9fe74fcf9560632cf2695058d47d8683b) # reset_artifacts: -10 # build_abe binutils: -9 # build_abe stage1 -- --set gcc_override_configure=--with-mode=thumb --set gcc_override_configure=--disable-libsanitizer: -8 # build_abe linux: -7 # build_abe glibc: -6 # build_abe stage2 -- --set gcc_override_configure=--with-mode=thumb --set gcc_override_configure=--disable-libsanitizer: -5 # build_llvm true: -3 # true: 0 # benchmark -Os_mthumb -- artifacts/build-3a2b05f9fe74fcf9560632cf2695058d47d8683b/results_id: 1 # 401.bzip2,bzip2_base.default regressed by 104
from (for last_good == 7294ca3f6ecacd05a197bbf0637e10afcb99b6d6) # reset_artifacts: -10 # build_abe binutils: -9 # build_abe stage1 -- --set gcc_override_configure=--with-mode=thumb --set gcc_override_configure=--disable-libsanitizer: -8 # build_abe linux: -7 # build_abe glibc: -6 # build_abe stage2 -- --set gcc_override_configure=--with-mode=thumb --set gcc_override_configure=--disable-libsanitizer: -5 # build_llvm true: -3 # true: 0 # benchmark -Os_mthumb -- artifacts/build-7294ca3f6ecacd05a197bbf0637e10afcb99b6d6/results_id: 1
Artifacts of last_good build: https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-... Results ID of last_good: tk1_32/tcwg_bmk_llvm_tk1/bisect-llvm-release-arm-spec2k6-Os/699 Artifacts of first_bad build: https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-... Results ID of first_bad: tk1_32/tcwg_bmk_llvm_tk1/bisect-llvm-release-arm-spec2k6-Os/688 Build top page/logs: https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-...
Configuration details:
Reproduce builds: <cut> mkdir investigate-llvm-3a2b05f9fe74fcf9560632cf2695058d47d8683b cd investigate-llvm-3a2b05f9fe74fcf9560632cf2695058d47d8683b
git clone https://git.linaro.org/toolchain/jenkins-scripts
mkdir -p artifacts/manifests curl -o artifacts/manifests/build-baseline.sh https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-... --fail curl -o artifacts/manifests/build-parameters.sh https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-... --fail curl -o artifacts/test.sh https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-... --fail chmod +x artifacts/test.sh
# Reproduce the baseline build (build all pre-requisites) ./jenkins-scripts/tcwg_bmk-build.sh @@ artifacts/manifests/build-baseline.sh
cd llvm
# Reproduce first_bad build git checkout --detach 3a2b05f9fe74fcf9560632cf2695058d47d8683b ../artifacts/test.sh
# Reproduce last_good build git checkout --detach 7294ca3f6ecacd05a197bbf0637e10afcb99b6d6 ../artifacts/test.sh
cd .. </cut>
History of pending regressions and results: https://git.linaro.org/toolchain/ci/base-artifacts.git/log/?h=linaro-local/c...
Artifacts: https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-... Build log: https://ci.linaro.org/job/tcwg_bmk_ci_llvm-bisect-tcwg_bmk_tk1-llvm-release-...
Full commit (up to 1000 lines): <cut> commit 3a2b05f9fe74fcf9560632cf2695058d47d8683b Author: Evgeniy Brevnov ybrevnov@azul.com Date: Fri Jul 24 18:57:10 2020 +0700
[BPI][NFC] Consolidate code to deal with SCCs under a dedicated data structure.
In order to facilitate review of D79485 here is a small NFC change which restructures code around handling of SCCs in BPI.
Reviewed By: davidxl
Differential Revision: https://reviews.llvm.org/D84514 --- llvm/include/llvm/Analysis/BranchProbabilityInfo.h | 71 ++++++++- llvm/lib/Analysis/BranchProbabilityInfo.cpp | 164 +++++++++++++-------- 2 files changed, 169 insertions(+), 66 deletions(-)
diff --git a/llvm/include/llvm/Analysis/BranchProbabilityInfo.h b/llvm/include/llvm/Analysis/BranchProbabilityInfo.h index 3e72afba36c3..7feb5b625938 100644 --- a/llvm/include/llvm/Analysis/BranchProbabilityInfo.h +++ b/llvm/include/llvm/Analysis/BranchProbabilityInfo.h @@ -151,13 +151,66 @@ public: /// Forget analysis results for the given basic block. void eraseBlock(const BasicBlock *BB);
- // Use to track SCCs for handling irreducible loops. - using SccMap = DenseMap<const BasicBlock *, int>; - using SccHeaderMap = DenseMap<const BasicBlock *, bool>; - using SccHeaderMaps = std::vector<SccHeaderMap>; - struct SccInfo { + class SccInfo { + // Enum of types to classify basic blocks in SCC. Basic block belonging to + // SCC is 'Inner' until it is either 'Header' or 'Exiting'. Note that a + // basic block can be 'Header' and 'Exiting' at the same time. + enum SccBlockType { + Inner = 0x0, + Header = 0x1, + Exiting = 0x2, + }; + // Map of basic blocks to SCC IDs they belong to. If basic block doesn't + // belong to any SCC it is not in the map. + using SccMap = DenseMap<const BasicBlock *, int>; + // Each basic block in SCC is attributed with one or several types from + // SccBlockType. Map value has uint32_t type (instead of SccBlockType) + // since basic block may be for example "Header" and "Exiting" at the same + // time and we need to be able to keep more than one value from + // SccBlockType. + using SccBlockTypeMap = DenseMap<const BasicBlock *, uint32_t>; + // Vector containing classification of basic blocks for all SCCs where i'th + // vector element corresponds to SCC with ID equal to i. + using SccBlockTypeMaps = std::vector<SccBlockTypeMap>; + SccMap SccNums; - SccHeaderMaps SccHeaders; + SccBlockTypeMaps SccBlocks; + + public: + explicit SccInfo(const Function &F); + + /// If \p BB belongs to some SCC then ID of that SCC is returned, otherwise + /// -1 is returned. If \p BB belongs to more than one SCC at the same time + /// result is undefined. + int getSCCNum(const BasicBlock *BB) const; + /// Returns true if \p BB is a 'header' block in SCC with \p SccNum ID, + /// false otherwise. + bool isSCCHeader(const BasicBlock *BB, int SccNum) const { + return getSccBlockType(BB, SccNum) & Header; + } + /// Returns true if \p BB is an 'exiting' block in SCC with \p SccNum ID, + /// false otherwise. + bool isSCCExitingBlock(const BasicBlock *BB, int SccNum) const { + return getSccBlockType(BB, SccNum) & Exiting; + } + /// Fills in \p Enters vector with all such blocks that don't belong to + /// SCC with \p SccNum ID but there is an edge to a block belonging to the + /// SCC. + void getSccEnterBlocks(int SccNum, + SmallVectorImpl<BasicBlock *> &Enters) const; + /// Fills in \p Exits vector with all such blocks that don't belong to + /// SCC with \p SccNum ID but there is an edge from a block belonging to the + /// SCC. + void getSccExitBlocks(int SccNum, + SmallVectorImpl<BasicBlock *> &Exits) const; + + private: + /// Returns \p BB's type according to classification given by SccBlockType + /// enum. Please note that \p BB must belong to SSC with \p SccNum ID. + uint32_t getSccBlockType(const BasicBlock *BB, int SccNum) const; + /// Calculates \p BB's type and stores it in internal data structures for + /// future use. Please note that \p BB must belong to SSC with \p SccNum ID. + void calculateSccBlockType(const BasicBlock *BB, int SccNum); };
private: @@ -196,6 +249,9 @@ private: /// Track the last function we run over for printing. const Function *LastF = nullptr;
+ /// Keeps information about all SCCs in a function. + std::unique_ptr<const SccInfo> SccI; + /// Track the set of blocks directly succeeded by a returning block. SmallPtrSet<const BasicBlock *, 16> PostDominatedByUnreachable;
@@ -210,8 +266,7 @@ private: bool calcMetadataWeights(const BasicBlock *BB); bool calcColdCallHeuristics(const BasicBlock *BB); bool calcPointerHeuristics(const BasicBlock *BB); - bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI, - SccInfo &SccI); + bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI); bool calcZeroHeuristics(const BasicBlock *BB, const TargetLibraryInfo *TLI); bool calcFloatingPointHeuristics(const BasicBlock *BB); bool calcInvokeHeuristics(const BasicBlock *BB); diff --git a/llvm/lib/Analysis/BranchProbabilityInfo.cpp b/llvm/lib/Analysis/BranchProbabilityInfo.cpp index a396b5ad21c6..195fc69d9601 100644 --- a/llvm/lib/Analysis/BranchProbabilityInfo.cpp +++ b/llvm/lib/Analysis/BranchProbabilityInfo.cpp @@ -148,6 +148,105 @@ static const uint32_t IH_TAKEN_WEIGHT = 1024 * 1024 - 1; /// instruction. This is essentially never taken. static const uint32_t IH_NONTAKEN_WEIGHT = 1;
+BranchProbabilityInfo::SccInfo::SccInfo(const Function &F) { + // Record SCC numbers of blocks in the CFG to identify irreducible loops. + // FIXME: We could only calculate this if the CFG is known to be irreducible + // (perhaps cache this info in LoopInfo if we can easily calculate it there?). + int SccNum = 0; + for (scc_iterator<const Function *> It = scc_begin(&F); !It.isAtEnd(); + ++It, ++SccNum) { + // Ignore single-block SCCs since they either aren't loops or LoopInfo will + // catch them. + const std::vector<const BasicBlock *> &Scc = *It; + if (Scc.size() == 1) + continue; + + LLVM_DEBUG(dbgs() << "BPI: SCC " << SccNum << ":"); + for (const auto *BB : Scc) { + LLVM_DEBUG(dbgs() << " " << BB->getName()); + SccNums[BB] = SccNum; + calculateSccBlockType(BB, SccNum); + } + LLVM_DEBUG(dbgs() << "\n"); + } +} + +int BranchProbabilityInfo::SccInfo::getSCCNum(const BasicBlock *BB) const { + auto SccIt = SccNums.find(BB); + if (SccIt == SccNums.end()) + return -1; + return SccIt->second; +} + +void BranchProbabilityInfo::SccInfo::getSccEnterBlocks( + int SccNum, SmallVectorImpl<BasicBlock *> &Enters) const { + + for (auto MapIt : SccBlocks[SccNum]) { + const auto *BB = MapIt.first; + if (isSCCHeader(BB, SccNum)) + for (const auto *Pred : predecessors(BB)) + if (getSCCNum(Pred) != SccNum) + Enters.push_back(const_cast<BasicBlock *>(BB)); + } +} + +void BranchProbabilityInfo::SccInfo::getSccExitBlocks( + int SccNum, SmallVectorImpl<BasicBlock *> &Exits) const { + for (auto MapIt : SccBlocks[SccNum]) { + const auto *BB = MapIt.first; + if (isSCCExitingBlock(BB, SccNum)) + for (const auto *Succ : successors(BB)) + if (getSCCNum(Succ) != SccNum) + Exits.push_back(const_cast<BasicBlock *>(BB)); + } +} + +uint32_t BranchProbabilityInfo::SccInfo::getSccBlockType(const BasicBlock *BB, + int SccNum) const { + assert(getSCCNum(BB) == SccNum); + + assert(SccBlocks.size() > static_cast<unsigned>(SccNum) && "Unknown SCC"); + const auto &SccBlockTypes = SccBlocks[SccNum]; + + auto It = SccBlockTypes.find(BB); + if (It != SccBlockTypes.end()) { + return It->second; + } + return Inner; +} + +void BranchProbabilityInfo::SccInfo::calculateSccBlockType(const BasicBlock *BB, + int SccNum) { + assert(getSCCNum(BB) == SccNum); + uint32_t BlockType = Inner; + + if (llvm::any_of(make_range(pred_begin(BB), pred_end(BB)), + [&](const BasicBlock *Pred) { + // Consider any block that is an entry point to the SCC as + // a header. + return getSCCNum(Pred) != SccNum; + })) + BlockType |= Header; + + if (llvm::any_of( + make_range(succ_begin(BB), succ_end(BB)), + [&](const BasicBlock *Succ) { return getSCCNum(Succ) != SccNum; })) + BlockType |= Exiting; + + // Lazily compute the set of headers for a given SCC and cache the results + // in the SccHeaderMap. + if (SccBlocks.size() <= static_cast<unsigned>(SccNum)) + SccBlocks.resize(SccNum + 1); + auto &SccBlockTypes = SccBlocks[SccNum]; + + if (BlockType != Inner) { + bool IsInserted; + std::tie(std::ignore, IsInserted) = + SccBlockTypes.insert(std::make_pair(BB, BlockType)); + assert(IsInserted && "Duplicated block in SCC"); + } +} + static void UpdatePDTWorklist(const BasicBlock *BB, PostDominatorTree *PDT, SmallVectorImpl<const BasicBlock *> &WorkList, SmallPtrSetImpl<const BasicBlock *> &TargetSet) { @@ -511,38 +610,6 @@ bool BranchProbabilityInfo::calcPointerHeuristics(const BasicBlock *BB) { return true; }
-static int getSCCNum(const BasicBlock *BB, - const BranchProbabilityInfo::SccInfo &SccI) { - auto SccIt = SccI.SccNums.find(BB); - if (SccIt == SccI.SccNums.end()) - return -1; - return SccIt->second; -} - -// Consider any block that is an entry point to the SCC as a header. -static bool isSCCHeader(const BasicBlock *BB, int SccNum, - BranchProbabilityInfo::SccInfo &SccI) { - assert(getSCCNum(BB, SccI) == SccNum); - - // Lazily compute the set of headers for a given SCC and cache the results - // in the SccHeaderMap. - if (SccI.SccHeaders.size() <= static_cast<unsigned>(SccNum)) - SccI.SccHeaders.resize(SccNum + 1); - auto &HeaderMap = SccI.SccHeaders[SccNum]; - bool Inserted; - BranchProbabilityInfo::SccHeaderMap::iterator HeaderMapIt; - std::tie(HeaderMapIt, Inserted) = HeaderMap.insert(std::make_pair(BB, false)); - if (Inserted) { - bool IsHeader = llvm::any_of(make_range(pred_begin(BB), pred_end(BB)), - [&](const BasicBlock *Pred) { - return getSCCNum(Pred, SccI) != SccNum; - }); - HeaderMapIt->second = IsHeader; - return IsHeader; - } else - return HeaderMapIt->second; -} - // Compute the unlikely successors to the block BB in the loop L, specifically // those that are unlikely because this is a loop, and add them to the // UnlikelyBlocks set. @@ -653,12 +720,11 @@ computeUnlikelySuccessors(const BasicBlock *BB, Loop *L, // Calculate Edge Weights using "Loop Branch Heuristics". Predict backedges // as taken, exiting edges as not-taken. bool BranchProbabilityInfo::calcLoopBranchHeuristics(const BasicBlock *BB, - const LoopInfo &LI, - SccInfo &SccI) { + const LoopInfo &LI) { int SccNum; Loop *L = LI.getLoopFor(BB); if (!L) { - SccNum = getSCCNum(BB, SccI); + SccNum = SccI->getSCCNum(BB); if (SccNum < 0) return false; } @@ -685,9 +751,9 @@ bool BranchProbabilityInfo::calcLoopBranchHeuristics(const BasicBlock *BB, else InEdges.push_back(I.getSuccessorIndex()); } else { - if (getSCCNum(*I, SccI) != SccNum) + if (SccI->getSCCNum(*I) != SccNum) ExitingEdges.push_back(I.getSuccessorIndex()); - else if (isSCCHeader(*I, SccNum, SccI)) + else if (SccI->isSCCHeader(*I, SccNum)) BackEdges.push_back(I.getSuccessorIndex()); else InEdges.push_back(I.getSuccessorIndex()); @@ -1072,26 +1138,7 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI, assert(PostDominatedByUnreachable.empty()); assert(PostDominatedByColdCall.empty());
- // Record SCC numbers of blocks in the CFG to identify irreducible loops. - // FIXME: We could only calculate this if the CFG is known to be irreducible - // (perhaps cache this info in LoopInfo if we can easily calculate it there?). - int SccNum = 0; - SccInfo SccI; - for (scc_iterator<const Function *> It = scc_begin(&F); !It.isAtEnd(); - ++It, ++SccNum) { - // Ignore single-block SCCs since they either aren't loops or LoopInfo will - // catch them. - const std::vector<const BasicBlock *> &Scc = *It; - if (Scc.size() == 1) - continue; - - LLVM_DEBUG(dbgs() << "BPI: SCC " << SccNum << ":"); - for (auto *BB : Scc) { - LLVM_DEBUG(dbgs() << " " << BB->getName()); - SccI.SccNums[BB] = SccNum; - } - LLVM_DEBUG(dbgs() << "\n"); - } + SccI = std::make_unique<SccInfo>(F);
std::unique_ptr<PostDominatorTree> PDTPtr;
@@ -1119,7 +1166,7 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI, continue; if (calcColdCallHeuristics(BB)) continue; - if (calcLoopBranchHeuristics(BB, LI, SccI)) + if (calcLoopBranchHeuristics(BB, LI)) continue; if (calcPointerHeuristics(BB)) continue; @@ -1131,6 +1178,7 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI,
PostDominatedByUnreachable.clear(); PostDominatedByColdCall.clear(); + SccI.release();
if (PrintBranchProb && (PrintBranchProbFuncName.empty() || </cut>