[llvm] [NFC][Coverage] Do not use recursion for GCOV propagateCounts. (PR #68455)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 6 15:20:46 PDT 2023
https://github.com/shen3qing1 created https://github.com/llvm/llvm-project/pull/68455
This causes stack overflows for some real-world kernel libraries.
Ran $ build/bin/llvm-lit -a llvm/test/tools/llvm-cov locally and passed.
>From cf6f2a4122c6f89cc23243308c015ca3e1db14b7 Mon Sep 17 00:00:00 2001
From: Qing Shen <qingshen at google.com>
Date: Fri, 6 Oct 2023 20:25:00 +0000
Subject: [PATCH] [NFC][Coverage] Do not use recursion for GCOV
propagateCounts.
This causes stack overflows for some real-world kernel libraries.
Ran $ build/bin/llvm-lit -a llvm/test/tools/llvm-cov locally and passed.
---
llvm/lib/ProfileData/GCOV.cpp | 90 ++++++++++++++++++++++++++++-------
1 file changed, 73 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp
index 0a3330fde1d100f..6edd47c440b9f13 100644
--- a/llvm/lib/ProfileData/GCOV.cpp
+++ b/llvm/lib/ProfileData/GCOV.cpp
@@ -366,24 +366,80 @@ GCOVBlock &GCOVFunction::getExitBlock() const {
// outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
// spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
// uniquely identified.
-uint64_t GCOVFunction::propagateCounts(const GCOVBlock &v, GCOVArc *pred) {
- // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
- // this prevents infinite recursion.
- if (!visited.insert(&v).second)
- return 0;
+uint64_t GCOVFunction::propagateCounts(const GCOVBlock &V, GCOVArc *Pred) {
+ struct StackElem {
+ const GCOVBlock &Block;
+ GCOVArc *Pred;
+ size_t PrevStackElemIdx;
+ uint64_t Excess = 0;
+ bool IsInSrcs = true;
+ bool Visited = false;
+ };
+
+ std::vector<StackElem> BlockStack;
+ BlockStack.push_back({V, nullptr, 0});
+
+ while (!BlockStack.empty()) {
+ StackElem &Current = BlockStack.back();
+ size_t Idx = BlockStack.size() - 1;
+
+ if (!Current.Visited) {
+ Current.Visited = true;
+ // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed;
+ // otherwise this prevents infinite recursion.
+ if (!visited.insert(&Current.Block).second) {
+ BlockStack.pop_back();
+ continue;
+ }
+
+ std::vector<StackElem> ChildBlockStack;
+ for (GCOVArc *E : Current.Block.srcs()) {
+ if (E != Current.Pred) {
+ if (E->onTree()) {
+ ChildBlockStack.push_back({E->src, E, Idx});
+ } else {
+ Current.Excess += E->count;
+ }
+ }
+ }
+
+ for (GCOVArc *E : Current.Block.dsts()) {
+ if (E != Current.Pred) {
+ if (E->onTree()) {
+ ChildBlockStack.push_back({E->dst, E, Idx, 0, false});
+ } else {
+ Current.Excess -= E->count;
+ }
+ }
+ }
+
+ for (auto &E : ChildBlockStack)
+ BlockStack.emplace_back(std::move(E));
+ } else {
+ // second visit, ready to pop out the value
+ // Excess is already calculated from the children
+ if (static_cast<int64_t>(Current.Excess) < 0)
+ Current.Excess = -Current.Excess;
- uint64_t excess = 0;
- for (GCOVArc *e : v.srcs())
- if (e != pred)
- excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
- for (GCOVArc *e : v.dsts())
- if (e != pred)
- excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
- if (int64_t(excess) < 0)
- excess = -excess;
- if (pred)
- pred->count = excess;
- return excess;
+ if (Idx == 0) {
+ return Current.Excess;
+ }
+
+ if (Current.Pred)
+ Current.Pred->count = Current.Excess;
+
+ // updates parent Excess value
+ if (Current.IsInSrcs) {
+ BlockStack[Current.PrevStackElemIdx].Excess += Current.Excess;
+ } else {
+ BlockStack[Current.PrevStackElemIdx].Excess -= Current.Excess;
+ }
+
+ BlockStack.pop_back();
+ }
+ }
+
+ return 0;
}
void GCOVFunction::print(raw_ostream &OS) const {
More information about the llvm-commits
mailing list