[llvm] [DebugCounter] Add support for non-continous ranges. (PR #89470)
via llvm-commits
llvm-commits at lists.llvm.org
Mon May 20 12:16:51 PDT 2024
https://github.com/Ralender updated https://github.com/llvm/llvm-project/pull/89470
>From 3dea0ba1f928921eff83d9b9537dd474cba0012a Mon Sep 17 00:00:00 2001
From: Tyker <tyker1 at outlook.com>
Date: Mon, 20 May 2024 20:06:48 +0200
Subject: [PATCH] [DebugCounter] Add support for non-continous ranges.
---
llvm/docs/ProgrammersManual.rst | 38 +++-
llvm/include/llvm/Support/DebugCounter.h | 88 ++++----
llvm/lib/Support/DebugCounter.cpp | 194 +++++++++++++-----
llvm/lib/Transforms/Scalar/NewGVN.cpp | 6 +-
.../ValueTracking/assume-queries-counter.ll | 6 +-
.../AArch64/GlobalISel/counter-fallback.ll | 4 +-
llvm/test/CodeGen/AMDGPU/waitcnt-debug.mir | 8 +-
llvm/test/CodeGen/X86/dag-combine-counter.ll | 2 +-
.../Other/X86/debugcounter-divrempairs.ll | 2 +-
.../debugcounter-partiallyinlinelibcalls.ll | 2 +-
llvm/test/Other/debugcounter-dce.ll | 2 +-
llvm/test/Other/debugcounter-earlycse.ll | 2 +-
llvm/test/Other/debugcounter-newgvn.ll | 2 +-
llvm/test/Other/debugcounter-predicateinfo.ll | 2 +-
llvm/test/Other/print-debug-counter.ll | 10 +-
.../DeadStoreElimination/debug-counter.ll | 8 +-
.../Transforms/Util/assume-builder-counter.ll | 6 +-
llvm/tools/reduce-chunk-list/CMakeLists.txt | 9 +
.../reduce-chunk-list/reduce-chunk-list.cpp | 147 +++++++++++++
llvm/unittests/Support/DebugCounterTest.cpp | 28 +--
20 files changed, 426 insertions(+), 140 deletions(-)
create mode 100644 llvm/tools/reduce-chunk-list/CMakeLists.txt
create mode 100644 llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst
index 491e6b1dd2498..f4a16c43d4499 100644
--- a/llvm/docs/ProgrammersManual.rst
+++ b/llvm/docs/ProgrammersManual.rst
@@ -1362,16 +1362,14 @@ Whatever code you want that control, use ``DebugCounter::shouldExecute`` to cont
if (DebugCounter::shouldExecute(DeleteAnInstruction))
I->eraseFromParent();
-That's all you have to do. Now, using opt, you can control when this code triggers using
-the '``--debug-counter``' option. There are two counters provided, ``skip`` and ``count``.
-``skip`` is the number of times to skip execution of the codepath. ``count`` is the number
-of times, once we are done skipping, to execute the codepath.
+That's all you have to do. Now, using opt, you can control when this code triggers using
+the '``--debug-counter``' Options.To specify when to execute the codepath.
.. code-block:: none
- $ opt --debug-counter=passname-delete-instruction-skip=1,passname-delete-instruction-count=2 -passname
+ $ opt --debug-counter=passname-delete-instruction=2-3 -passname
-This will skip the above code the first time we hit it, then execute it twice, then skip the rest of the executions.
+This will skip the above code the first two times we hit it, then execute it 2 times, then skip the rest of the executions.
So if executed on the following code:
@@ -1385,8 +1383,32 @@ So if executed on the following code:
It would delete number ``%2`` and ``%3``.
A utility is provided in `utils/bisect-skip-count` to binary search
-skip and count arguments. It can be used to automatically minimize the
-skip and count for a debug-counter variable.
+the begin and end of the range argument. It can be used to automatically minimize the
+range for a debug-counter variable.
+
+A more general utility is provided in `llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp` to minimize debug counter chunks lists.
+
+How to use reduce-chunk-list:
+First, Figure out the number of calls to the debug counter you want to minimize.
+To do so, run the compilation command causing you want to minimize with `-print-debug-counter` adding a `-mllvm` if needed.
+Than find the line with the counter of interest. it should look like:
+.. code-block:: none
+
+ my-counter : {5678,empty}
+
+The number of calls to `my-counter` is 5678
+
+Than Find the minimum set of chunks that is interesting, with `reduce-chunk-list`.
+Build a reproducer script like:
+.. code-block:: bash
+
+ #! /bin/bash
+ opt -debug-counter=my-counter=$1
+ # ... Test result of the command. Failure of the script is considered interesting
+
+Than run `reduce-chunk-list my-script.sh 0-5678 2>&1 | tee dump_bisect`
+This command may take some time.
+but when it is done, it will print the result like: `Minimal Chunks = 0:1:5:11-12:33-34`
.. _ViewGraph:
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index 9fa4620ade3c8..e4345e5739e99 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -17,14 +17,13 @@
/// debug. That is where debug counting steps in. You can instrument the pass
/// with a debug counter before it does a certain thing, and depending on the
/// counts, it will either execute that thing or not. The debug counter itself
-/// consists of a skip and a count. Skip is the number of times shouldExecute
-/// needs to be called before it returns true. Count is the number of times to
-/// return true once Skip is 0. So a skip=47, count=2 ,would skip the first 47
-/// executions by returning false from shouldExecute, then execute twice, and
-/// then return false again.
-/// Note that a counter set to a negative number will always execute.
-/// For a concrete example, during predicateinfo creation, the renaming pass
-/// replaces each use with a renamed use.
+/// consists of a list of chunks (inclusive numeric ranges). `shouldExecute`
+/// returns true iff the list is empty or the current count is in one of the
+/// chunks.
+///
+/// Note that a counter set to a negative number will always execute. For a
+/// concrete example, during predicateinfo creation, the renaming pass replaces
+/// each use with a renamed use.
////
/// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and
/// variable name RenameCounter, and then instrument this renaming with a debug
@@ -34,15 +33,16 @@
/// <continue or return or whatever not executing looks like>
///
/// Now I can, from the command line, make it rename or not rename certain uses
-/// by setting the skip and count.
+/// by setting the chunk list.
/// So for example
-/// bin/opt -debug-counter=predicateinfo-skip=47,predicateinfo-count=1
+/// bin/opt -debug-counter=predicateinfo=47
/// will skip renaming the first 47 uses, then rename one, then skip the rest.
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_DEBUGCOUNTER_H
#define LLVM_SUPPORT_DEBUGCOUNTER_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/UniqueVector.h"
@@ -55,6 +55,19 @@ class raw_ostream;
class DebugCounter {
public:
+ struct Chunk {
+ int64_t Begin;
+ int64_t End;
+ void print(llvm::raw_ostream &OS);
+ bool contains(int64_t Idx) { return Idx >= Begin && Idx <= End; }
+ };
+
+ static void printChunks(raw_ostream &OS, ArrayRef<Chunk>);
+
+ /// Return true on parsing error and print the error message on the
+ /// llvm::errs()
+ static bool parseChunks(StringRef Str, SmallVector<Chunk> &Res);
+
/// Returns a reference to the singleton instance.
static DebugCounter &instance();
@@ -69,29 +82,12 @@ class DebugCounter {
static unsigned registerCounter(StringRef Name, StringRef Desc) {
return instance().addCounter(std::string(Name), std::string(Desc));
}
+ static bool shouldExecuteImpl(unsigned CounterName);
+
inline static bool shouldExecute(unsigned CounterName) {
if (!isCountingEnabled())
return true;
-
- auto &Us = instance();
- auto Result = Us.Counters.find(CounterName);
- if (Result != Us.Counters.end()) {
- auto &CounterInfo = Result->second;
- ++CounterInfo.Count;
-
- // We only execute while the Skip is not smaller than Count,
- // and the StopAfter + Skip is larger than Count.
- // Negative counters always execute.
- if (CounterInfo.Skip < 0)
- return true;
- if (CounterInfo.Skip >= CounterInfo.Count)
- return false;
- if (CounterInfo.StopAfter < 0)
- return true;
- return CounterInfo.StopAfter + CounterInfo.Skip >= CounterInfo.Count;
- }
- // Didn't find the counter, should we warn?
- return true;
+ return shouldExecuteImpl(CounterName);
}
// Return true if a given counter had values set (either programatically or on
@@ -101,18 +97,25 @@ class DebugCounter {
return instance().Counters[ID].IsSet;
}
- // Return the Count for a counter. This only works for set counters.
- static int64_t getCounterValue(unsigned ID) {
+ struct CounterState {
+ int64_t Count;
+ uint64_t ChunkIdx;
+ };
+
+ // Return the state of a counter. This only works for set counters.
+ static CounterState getCounterState(unsigned ID) {
auto &Us = instance();
auto Result = Us.Counters.find(ID);
assert(Result != Us.Counters.end() && "Asking about a non-set counter");
- return Result->second.Count;
+ return {Result->second.Count, Result->second.CurrChunkIdx};
}
- // Set a registered counter to a given Count value.
- static void setCounterValue(unsigned ID, int64_t Count) {
+ // Set a registered counter to a given state.
+ static void setCounterState(unsigned ID, CounterState State) {
auto &Us = instance();
- Us.Counters[ID].Count = Count;
+ auto &Counter = Us.Counters[ID];
+ Counter.Count = State.Count;
+ Counter.CurrChunkIdx = State.ChunkIdx;
}
// Dump or print the current counter set into llvm::dbgs().
@@ -152,11 +155,11 @@ class DebugCounter {
#ifdef NDEBUG
return false;
#else
- return instance().Enabled;
+ return instance().Enabled || instance().ShouldPrintCounter;
#endif
}
-private:
+protected:
unsigned addCounter(const std::string &Name, const std::string &Desc) {
unsigned Result = RegisteredCounters.insert(Name);
Counters[Result] = {};
@@ -166,17 +169,22 @@ class DebugCounter {
// Struct to store counter info.
struct CounterInfo {
int64_t Count = 0;
- int64_t Skip = 0;
- int64_t StopAfter = -1;
+ uint64_t CurrChunkIdx = 0;
bool IsSet = false;
std::string Desc;
+ SmallVector<Chunk> Chunks;
};
+
DenseMap<unsigned, CounterInfo> Counters;
CounterVector RegisteredCounters;
// Whether we should do DebugCounting at all. DebugCounters aren't
// thread-safe, so this should always be false in multithreaded scenarios.
bool Enabled = false;
+
+ bool ShouldPrintCounter = false;
+
+ bool BreakOnLast = false;
};
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 502665d2a8348..a5d8a704bdd21 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -7,6 +7,83 @@
using namespace llvm;
+namespace llvm {
+
+void DebugCounter::Chunk::print(llvm::raw_ostream &OS) {
+ if (Begin == End)
+ OS << Begin;
+ else
+ OS << Begin << "-" << End;
+}
+
+void DebugCounter::printChunks(raw_ostream &OS, ArrayRef<Chunk> Chunks) {
+ if (Chunks.empty()) {
+ OS << "empty";
+ } else {
+ bool IsFirst = true;
+ for (auto E : Chunks) {
+ if (!IsFirst)
+ OS << ':';
+ else
+ IsFirst = false;
+ E.print(OS);
+ }
+ }
+}
+
+bool DebugCounter::parseChunks(StringRef Str, SmallVector<Chunk> &Chunks) {
+ StringRef Remaining = Str;
+
+ auto ConsumeInt = [&]() -> int64_t {
+ StringRef Number =
+ Remaining.take_until([](char c) { return c < '0' || c > '9'; });
+ int64_t Res;
+ if (Number.getAsInteger(10, Res)) {
+ errs() << "Failed to parse int at : " << Remaining << "\n";
+ return -1;
+ }
+ Remaining = Remaining.drop_front(Number.size());
+ return Res;
+ };
+
+ while (1) {
+ int64_t Num = ConsumeInt();
+ if (Num == -1)
+ return true;
+ if (!Chunks.empty() && Num <= Chunks[Chunks.size() - 1].End) {
+ errs() << "Expected Chunks to be in increasing order " << Num
+ << " <= " << Chunks[Chunks.size() - 1].End << "\n";
+ return true;
+ }
+ if (Remaining.starts_with("-")) {
+ Remaining = Remaining.drop_front();
+ int64_t Num2 = ConsumeInt();
+ if (Num2 == -1)
+ return true;
+ if (Num >= Num2) {
+ errs() << "Expected " << Num << " < " << Num2 << " in " << Num << "-"
+ << Num2 << "\n";
+ return true;
+ }
+
+ Chunks.push_back({Num, Num2});
+ } else {
+ Chunks.push_back({Num, Num});
+ }
+ if (Remaining.starts_with(":")) {
+ Remaining = Remaining.drop_front();
+ continue;
+ }
+ if (Remaining.empty())
+ break;
+ errs() << "Failed to parse at : " << Remaining;
+ return true;
+ }
+ return false;
+}
+
+} // namespace llvm
+
namespace {
// This class overrides the default list implementation of printing so we
// can pretty print the list of debug counter options. This type of
@@ -47,15 +124,26 @@ class DebugCounterList : public cl::list<std::string, DebugCounter> {
// itself, are owned by a single global instance of the DebugCounterOwner
// struct. This makes it easier to control the order in which constructors and
// destructors are run.
-struct DebugCounterOwner {
- DebugCounter DC;
+struct DebugCounterOwner : DebugCounter {
DebugCounterList DebugCounterOption{
"debug-counter", cl::Hidden,
cl::desc("Comma separated list of debug counter skip and count"),
- cl::CommaSeparated, cl::location(DC)};
- cl::opt<bool> PrintDebugCounter{
- "print-debug-counter", cl::Hidden, cl::init(false), cl::Optional,
+ cl::CommaSeparated, cl::location<DebugCounter>(*this)};
+ cl::opt<bool, true> PrintDebugCounter{
+ "print-debug-counter",
+ cl::Hidden,
+ cl::Optional,
+ cl::location(this->ShouldPrintCounter),
+ cl::init(false),
cl::desc("Print out debug counter info after all counters accumulated")};
+ cl::opt<bool, true> BreakOnLastCount{
+ "debug-counter-break-on-last",
+ cl::Hidden,
+ cl::Optional,
+ cl::location(this->BreakOnLast),
+ cl::init(false),
+ cl::desc("Insert a break point on the last enabled count of a "
+ "chunks list")};
DebugCounterOwner() {
// Our destructor uses the debug stream. By referencing it here, we
@@ -65,8 +153,8 @@ struct DebugCounterOwner {
// Print information when destroyed, iff command line option is specified.
~DebugCounterOwner() {
- if (DC.isCountingEnabled() && PrintDebugCounter)
- DC.print(dbgs());
+ if (ShouldPrintCounter)
+ print(dbgs());
}
};
@@ -76,7 +164,7 @@ void llvm::initDebugCounterOptions() { (void)DebugCounter::instance(); }
DebugCounter &DebugCounter::instance() {
static DebugCounterOwner O;
- return O.DC;
+ return O;
}
// This is called by the command line parser when it sees a value for the
@@ -84,52 +172,31 @@ DebugCounter &DebugCounter::instance() {
void DebugCounter::push_back(const std::string &Val) {
if (Val.empty())
return;
- // The strings should come in as counter=value
+
+ // The strings should come in as counter=chunk_list
auto CounterPair = StringRef(Val).split('=');
if (CounterPair.second.empty()) {
errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";
return;
}
- // Now we have counter=value.
- // First, process value.
- int64_t CounterVal;
- if (CounterPair.second.getAsInteger(0, CounterVal)) {
- errs() << "DebugCounter Error: " << CounterPair.second
- << " is not a number\n";
+ StringRef CounterName = CounterPair.first;
+ SmallVector<Chunk> Chunks;
+
+ if (parseChunks(CounterPair.second, Chunks)) {
return;
}
- // Now we need to see if this is the skip or the count, remove the suffix, and
- // add it to the counter values.
- if (CounterPair.first.ends_with("-skip")) {
- auto CounterName = CounterPair.first.drop_back(5);
- unsigned CounterID = getCounterId(std::string(CounterName));
- if (!CounterID) {
- errs() << "DebugCounter Error: " << CounterName
- << " is not a registered counter\n";
- return;
- }
- enableAllCounters();
- CounterInfo &Counter = Counters[CounterID];
- Counter.Skip = CounterVal;
- Counter.IsSet = true;
- } else if (CounterPair.first.ends_with("-count")) {
- auto CounterName = CounterPair.first.drop_back(6);
- unsigned CounterID = getCounterId(std::string(CounterName));
- if (!CounterID) {
- errs() << "DebugCounter Error: " << CounterName
- << " is not a registered counter\n";
- return;
- }
- enableAllCounters();
-
- CounterInfo &Counter = Counters[CounterID];
- Counter.StopAfter = CounterVal;
- Counter.IsSet = true;
- } else {
- errs() << "DebugCounter Error: " << CounterPair.first
- << " does not end with -skip or -count\n";
+ unsigned CounterID = getCounterId(std::string(CounterName));
+ if (!CounterID) {
+ errs() << "DebugCounter Error: " << CounterName
+ << " is not a registered counter\n";
+ return;
}
+ enableAllCounters();
+
+ CounterInfo &Counter = Counters[CounterID];
+ Counter.IsSet = true;
+ Counter.Chunks = std::move(Chunks);
}
void DebugCounter::print(raw_ostream &OS) const {
@@ -142,9 +209,42 @@ void DebugCounter::print(raw_ostream &OS) const {
for (auto &CounterName : CounterNames) {
unsigned CounterID = getCounterId(std::string(CounterName));
OS << left_justify(RegisteredCounters[CounterID], 32) << ": {"
- << Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip
- << "," << Us.Counters[CounterID].StopAfter << "}\n";
+ << Us.Counters[CounterID].Count << ",";
+ printChunks(OS, Us.Counters[CounterID].Chunks);
+ OS << "}\n";
+ }
+}
+
+bool DebugCounter::shouldExecuteImpl(unsigned CounterName) {
+ auto &Us = instance();
+ auto Result = Us.Counters.find(CounterName);
+ if (Result != Us.Counters.end()) {
+ auto &CounterInfo = Result->second;
+ int64_t CurrCount = CounterInfo.Count++;
+ uint64_t CurrIdx = CounterInfo.CurrChunkIdx;
+
+ if (CounterInfo.Chunks.empty())
+ return true;
+ if (CurrIdx >= CounterInfo.Chunks.size())
+ return false;
+
+ bool Res = CounterInfo.Chunks[CurrIdx].contains(CurrCount);
+ if (Us.BreakOnLast && CurrIdx == (CounterInfo.Chunks.size() - 1) &&
+ CurrCount == CounterInfo.Chunks[CurrIdx].End) {
+ LLVM_BUILTIN_DEBUGTRAP;
+ }
+ if (CurrCount > CounterInfo.Chunks[CurrIdx].End) {
+ CounterInfo.CurrChunkIdx++;
+
+ /// Handle consecutive blocks.
+ if (CounterInfo.CurrChunkIdx < CounterInfo.Chunks.size() &&
+ CurrCount == CounterInfo.Chunks[CounterInfo.CurrChunkIdx].Begin)
+ return true;
+ }
+ return Res;
}
+ // Didn't find the counter, should we warn?
+ return true;
}
LLVM_DUMP_METHOD void DebugCounter::dump() const {
diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp
index 056be8629b961..40a6a89d23c2c 100644
--- a/llvm/lib/Transforms/Scalar/NewGVN.cpp
+++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp
@@ -892,7 +892,7 @@ class NewGVN {
// Debug counter info. When verifying, we have to reset the value numbering
// debug counter to the same state it started in to get the same results.
- int64_t StartingVNCounter = 0;
+ DebugCounter::CounterState StartingVNCounter;
};
} // end anonymous namespace
@@ -3278,7 +3278,7 @@ void NewGVN::verifyIterationSettled(Function &F) {
#ifndef NDEBUG
LLVM_DEBUG(dbgs() << "Beginning iteration verification\n");
if (DebugCounter::isCounterSet(VNCounter))
- DebugCounter::setCounterValue(VNCounter, StartingVNCounter);
+ DebugCounter::setCounterState(VNCounter, StartingVNCounter);
// Note that we have to store the actual classes, as we may change existing
// classes during iteration. This is because our memory iteration propagation
@@ -3423,7 +3423,7 @@ void NewGVN::iterateTouchedInstructions() {
// This is the main transformation entry point.
bool NewGVN::runGVN() {
if (DebugCounter::isCounterSet(VNCounter))
- StartingVNCounter = DebugCounter::getCounterValue(VNCounter);
+ StartingVNCounter = DebugCounter::getCounterState(VNCounter);
bool Changed = false;
NumFuncArgs = F.arg_size();
MSSAWalker = MSSA->getWalker();
diff --git a/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll b/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
index 3e93b5d244421..a53b90b7b448a 100644
--- a/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
+++ b/llvm/test/Analysis/ValueTracking/assume-queries-counter.ll
@@ -1,9 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; REQUIRES: asserts
-; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter-skip=0,assume-queries-counter-count=1 -S | FileCheck %s --check-prefixes=COUNTER1
-; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter-skip=1,assume-queries-counter-count=2 -S | FileCheck %s --check-prefixes=COUNTER2
-; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter-skip=2,assume-queries-counter-count=5 -S | FileCheck %s --check-prefixes=COUNTER3
+; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter=0 -S | FileCheck %s --check-prefixes=COUNTER1
+; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter=1-2 -S | FileCheck %s --check-prefixes=COUNTER2
+; RUN: opt < %s -passes=instcombine --debug-counter=assume-queries-counter=2-6 -S | FileCheck %s --check-prefixes=COUNTER3
declare i1 @get_val()
declare void @llvm.assume(i1)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/counter-fallback.ll b/llvm/test/CodeGen/AArch64/GlobalISel/counter-fallback.ll
index 9a39b5a2ad7a9..72c8103de875d 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/counter-fallback.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/counter-fallback.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
-; RUN: llc -mtriple=aarch64-- -global-isel -global-isel-abort=0 -debug-counter=globalisel-count=1 %s -o - 2>/dev/null | FileCheck %s
-; RUN: llc -mtriple=aarch64-- -global-isel -global-isel-abort=0 -debug-counter=globalisel-count=1 %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=DEBUG
+; RUN: llc -mtriple=aarch64-- -global-isel -global-isel-abort=0 -debug-counter=globalisel=0 %s -o - 2>/dev/null | FileCheck %s
+; RUN: llc -mtriple=aarch64-- -global-isel -global-isel-abort=0 -debug-counter=globalisel=0 %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=DEBUG
; REQUIRES: asserts
diff --git a/llvm/test/CodeGen/AMDGPU/waitcnt-debug.mir b/llvm/test/CodeGen/AMDGPU/waitcnt-debug.mir
index 641a31ab9b0f0..0e3656b498d33 100644
--- a/llvm/test/CodeGen/AMDGPU/waitcnt-debug.mir
+++ b/llvm/test/CodeGen/AMDGPU/waitcnt-debug.mir
@@ -1,8 +1,8 @@
# REQUIRES: asserts
-# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -debug-counter=si-insert-waitcnts-forcelgkm-count=1 -o - %s | FileCheck -check-prefixes=GCN,LGKM %s
-# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -debug-counter=si-insert-waitcnts-forceexp-count=2 -o - %s | FileCheck -check-prefixes=GCN,EXP %s
-# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -debug-counter=si-insert-waitcnts-forcevm-count=3 -o - %s | FileCheck -check-prefixes=GCN,VM %s
-# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -amdgpu-waitcnt-forcezero=1 -debug-counter=si-insert-waitcnts-forcevm-count=2 -o - %s | FileCheck -check-prefixes=GCN,ZERO %s
+# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -debug-counter=si-insert-waitcnts-forcelgkm=0 -o - %s | FileCheck -check-prefixes=GCN,LGKM %s
+# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -debug-counter=si-insert-waitcnts-forceexp=0-1 -o - %s | FileCheck -check-prefixes=GCN,EXP %s
+# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -debug-counter=si-insert-waitcnts-forcevm=0-2 -o - %s | FileCheck -check-prefixes=GCN,VM %s
+# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-insert-waitcnts -amdgpu-waitcnt-forcezero=1 -debug-counter=si-insert-waitcnts-forcevm=0-1 -o - %s | FileCheck -check-prefixes=GCN,ZERO %s
# check that the waitcnt pass options that force insertion of waitcnt instructions are working as expected
diff --git a/llvm/test/CodeGen/X86/dag-combine-counter.ll b/llvm/test/CodeGen/X86/dag-combine-counter.ll
index 8568db8d840a4..4cc3c71b2328c 100644
--- a/llvm/test/CodeGen/X86/dag-combine-counter.ll
+++ b/llvm/test/CodeGen/X86/dag-combine-counter.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
-; RUN: llc -mtriple=x86_64-- -debug-counter=dagcombine-count=6 < %s | FileCheck %s
+; RUN: llc -mtriple=x86_64-- -debug-counter=dagcombine=0-5 < %s | FileCheck %s
; REQUIRES: asserts
diff --git a/llvm/test/Other/X86/debugcounter-divrempairs.ll b/llvm/test/Other/X86/debugcounter-divrempairs.ll
index ed4b47a16d212..c196dcd01eca4 100644
--- a/llvm/test/Other/X86/debugcounter-divrempairs.ll
+++ b/llvm/test/Other/X86/debugcounter-divrempairs.ll
@@ -1,5 +1,5 @@
; REQUIRES: asserts
-; RUN: opt < %s -passes=div-rem-pairs -debug-counter=div-rem-pairs-transform-skip=1,div-rem-pairs-transform-count=1 \
+; RUN: opt < %s -passes=div-rem-pairs -debug-counter=div-rem-pairs-transform=1 \
; RUN: -S -mtriple=x86_64-unknown-unknown | FileCheck %s
;; Test that, with debug counters on, we only skip the first div-rem-pairs opportunity, optimize one after it,
;; and then ignore all the others. There is 1 optimization opportunity in f1, 2 in f2, and another 1 in f3,
diff --git a/llvm/test/Other/X86/debugcounter-partiallyinlinelibcalls.ll b/llvm/test/Other/X86/debugcounter-partiallyinlinelibcalls.ll
index 5fdb3c2b80912..8024c05feea3b 100644
--- a/llvm/test/Other/X86/debugcounter-partiallyinlinelibcalls.ll
+++ b/llvm/test/Other/X86/debugcounter-partiallyinlinelibcalls.ll
@@ -1,5 +1,5 @@
; REQUIRES: asserts
-; RUN: opt -S -debug-counter=partially-inline-libcalls-transform-skip=1,partially-inline-libcalls-transform-count=1 \
+; RUN: opt -S -debug-counter=partially-inline-libcalls-transform=1 \
; RUN: -passes=partially-inline-libcalls -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
;; Test that, with debug counters on, we will skip the first optimization opportunity, perform next 1,
;; and ignore all the others left.
diff --git a/llvm/test/Other/debugcounter-dce.ll b/llvm/test/Other/debugcounter-dce.ll
index 75302149e717a..54d929f219aef 100644
--- a/llvm/test/Other/debugcounter-dce.ll
+++ b/llvm/test/Other/debugcounter-dce.ll
@@ -1,5 +1,5 @@
; REQUIRES: asserts
-; RUN: opt -passes=dce -S -debug-counter=dce-transform-skip=1,dce-transform-count=2 < %s | FileCheck %s
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2 < %s | FileCheck %s
;; Test that, with debug counters on, we will skip the first DCE opportunity, perform next 2,
;; and ignore all the others left.
diff --git a/llvm/test/Other/debugcounter-earlycse.ll b/llvm/test/Other/debugcounter-earlycse.ll
index b3e74e05f8db3..d3628c760ca33 100644
--- a/llvm/test/Other/debugcounter-earlycse.ll
+++ b/llvm/test/Other/debugcounter-earlycse.ll
@@ -1,5 +1,5 @@
; REQUIRES: asserts
-; RUN: opt -S -debug-counter=early-cse-skip=1,early-cse-count=1 -passes=early-cse -earlycse-debug-hash < %s 2>&1 | FileCheck %s
+; RUN: opt -S -debug-counter=early-cse=1 -passes=early-cse -earlycse-debug-hash < %s 2>&1 | FileCheck %s
;; Test that, with debug counters on, we only optimize the second CSE opportunity.
define i32 @test(i32 %a, i32 %b) {
; CHECK-LABEL: @test(
diff --git a/llvm/test/Other/debugcounter-newgvn.ll b/llvm/test/Other/debugcounter-newgvn.ll
index 6ebca6016d3d8..fba21bd5de962 100644
--- a/llvm/test/Other/debugcounter-newgvn.ll
+++ b/llvm/test/Other/debugcounter-newgvn.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; REQUIRES: asserts
-; RUN: opt -S -debug-counter=newgvn-vn-skip=1,newgvn-vn-count=2 -passes=newgvn < %s 2>&1 | FileCheck %s
+; RUN: opt -S -debug-counter=newgvn-vn=1-2 -passes=newgvn < %s 2>&1 | FileCheck %s
;; Test that, with debug counters on, we don't value number the first instruction, only the second and third,
;; which means we do not discover the return is constant.
define i32 @vntest() {
diff --git a/llvm/test/Other/debugcounter-predicateinfo.ll b/llvm/test/Other/debugcounter-predicateinfo.ll
index 1f2b39dc62955..981bd1514f6e9 100644
--- a/llvm/test/Other/debugcounter-predicateinfo.ll
+++ b/llvm/test/Other/debugcounter-predicateinfo.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; REQUIRES: asserts
-; RUN: opt -debug-counter=predicateinfo-rename-skip=1,predicateinfo-rename-count=1 -passes=print-predicateinfo < %s 2>&1 | FileCheck %s
+; RUN: opt -debug-counter=predicateinfo-rename=1 -passes=print-predicateinfo < %s 2>&1 | FileCheck %s
;; Test that, with debug counters on, we don't rename the first info, only the second
define fastcc void @barney() {
; CHECK-LABEL: @barney(
diff --git a/llvm/test/Other/print-debug-counter.ll b/llvm/test/Other/print-debug-counter.ll
index 4b6e42570b315..0bba811f71c6d 100644
--- a/llvm/test/Other/print-debug-counter.ll
+++ b/llvm/test/Other/print-debug-counter.ll
@@ -1,16 +1,16 @@
; REQUIRES: asserts
-; RUN: opt -S -debug-counter=early-cse-skip=1,early-cse-count=1 -passes=early-cse,newgvn,instcombine -earlycse-debug-hash \
-; RUN: -debug-counter=newgvn-vn-skip=1,newgvn-vn-count=2 \
+; RUN: opt -S -debug-counter=early-cse=1 -passes=early-cse,newgvn,instcombine -earlycse-debug-hash \
+; RUN: -debug-counter=newgvn-vn=1-2 \
; RUN: -print-debug-counter < %s 2>&1 | FileCheck %s
;; Test debug counter prints correct info in right order.
; CHECK-LABEL: Counters and values:
; CHECK: early-cse
-; CHECK-SAME: {4,1,1}
+; CHECK-SAME: {4,1}
; CHECK: instcombine-visit
-; CHECK-SAME: {13,0,-1}
+; CHECK-SAME: {13,empty}
; CHECK: newgvn-vn
-; CHECK-SAME: {9,1,2}
+; CHECK-SAME: {9,1-2}
define i32 @f1(i32 %a, i32 %b) {
bb:
%add1 = add i32 %a, %b
diff --git a/llvm/test/Transforms/DeadStoreElimination/debug-counter.ll b/llvm/test/Transforms/DeadStoreElimination/debug-counter.ll
index 691b89d8d4ca9..ffa10e37c76f6 100644
--- a/llvm/test/Transforms/DeadStoreElimination/debug-counter.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/debug-counter.ll
@@ -3,16 +3,16 @@
; REQUIRES: asserts
; Eliminates store to %R in the entry block.
-; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa-skip=0,dse-memoryssa-count=1 -S | FileCheck --check-prefix=SKIP0-COUNT1 %s
+; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa=0 -S | FileCheck --check-prefix=SKIP0-COUNT1 %s
; Eliminates store to %P in the entry block.
-; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa-skip=1,dse-memoryssa-count=1 -S | FileCheck --check-prefix=SKIP1-COUNT1 %s
+; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa=1 -S | FileCheck --check-prefix=SKIP1-COUNT1 %s
; Eliminates both stores in the entry block.
-; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa-skip=0,dse-memoryssa-count=2 -S | FileCheck --check-prefix=SKIP0-COUNT2 %s
+; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa=0-1 -S | FileCheck --check-prefix=SKIP0-COUNT2 %s
; Eliminates no stores.
-; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa-skip=2,dse-memoryssa-count=1 -S | FileCheck --check-prefix=SKIP2-COUNT1 %s
+; RUN: opt < %s -passes=dse -debug-counter=dse-memoryssa=2 -S | FileCheck --check-prefix=SKIP2-COUNT1 %s
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
diff --git a/llvm/test/Transforms/Util/assume-builder-counter.ll b/llvm/test/Transforms/Util/assume-builder-counter.ll
index 794a8d0b8443f..c11a69a2c3cd7 100644
--- a/llvm/test/Transforms/Util/assume-builder-counter.ll
+++ b/llvm/test/Transforms/Util/assume-builder-counter.ll
@@ -1,9 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
; REQUIRES: asserts
-; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --debug-counter=assume-builder-counter-skip=5,assume-builder-counter-count=1 -S %s | FileCheck %s --check-prefixes=COUNTER1
-; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --debug-counter=assume-builder-counter-skip=1,assume-builder-counter-count=3 -S %s | FileCheck %s --check-prefixes=COUNTER2
-; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --debug-counter=assume-builder-counter-skip=2,assume-builder-counter-count=200 -S %s | FileCheck %s --check-prefixes=COUNTER3
+; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --debug-counter=assume-builder-counter=5 -S %s | FileCheck %s --check-prefixes=COUNTER1
+; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --debug-counter=assume-builder-counter=1-3 -S %s | FileCheck %s --check-prefixes=COUNTER2
+; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --debug-counter=assume-builder-counter=2-202 -S %s | FileCheck %s --check-prefixes=COUNTER3
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/llvm/tools/reduce-chunk-list/CMakeLists.txt b/llvm/tools/reduce-chunk-list/CMakeLists.txt
new file mode 100644
index 0000000000000..5af76597bffac
--- /dev/null
+++ b/llvm/tools/reduce-chunk-list/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_llvm_tool(reduce-chunk-list
+ reduce-chunk-list.cpp
+
+ DEPENDS
+ )
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
new file mode 100644
index 0000000000000..a819af6e5f1a0
--- /dev/null
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -0,0 +1,147 @@
+//===-- reduce-chunk-list.cpp - Reduce a chunks list to its minimal size --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// See the llvm-project/llvm/docs/ProgrammersManual.rst to see how to use this
+// tool
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DebugCounter.h"
+#include "llvm/Support/Program.h"
+
+using namespace llvm;
+
+cl::opt<std::string> ReproductionCmd(cl::Positional, cl::Required);
+
+cl::opt<std::string> StartChunks(cl::Positional, cl::Required);
+
+cl::opt<bool> Pessimist("pessimist", cl::init(false));
+
+using Chunk = DebugCounter::Chunk;
+
+namespace {
+
+SmallVector<Chunk> simplifyChunksList(ArrayRef<Chunk> Chunks) {
+ SmallVector<Chunk> Res;
+ Res.push_back(Chunks.front());
+ for (unsigned Idx = 1; Idx < Chunks.size(); Idx++) {
+ if (Chunks[Idx].Begin == Res.back().End + 1)
+ Res.back().End = Chunks[Idx].End;
+ else
+ Res.push_back(Chunks[Idx]);
+ }
+ return Res;
+}
+
+bool isStillInteresting(ArrayRef<Chunk> Chunks) {
+ SmallVector<Chunk> SimpleChunks = simplifyChunksList(Chunks);
+
+ std::string ChunkStr;
+ {
+ raw_string_ostream OS(ChunkStr);
+ DebugCounter::printChunks(OS, SimpleChunks);
+ }
+
+ errs() << "Checking with: " << ChunkStr << "\n";
+
+ std::vector<StringRef> Argv;
+ Argv.push_back(ReproductionCmd);
+ Argv.push_back(ChunkStr);
+
+ std::string ErrMsg;
+ bool ExecutionFailed;
+ int Result = sys::ExecuteAndWait(Argv[0], Argv, std::nullopt, {}, 0, 0,
+ &ErrMsg, &ExecutionFailed);
+ if (ExecutionFailed) {
+ errs() << "failed to execute : " << Argv[0] << " : " << ErrMsg << "\n";
+ exit(1);
+ }
+
+ bool Res = Result != 0;
+ if (Res) {
+ errs() << "SUCCESS : Still Interesting\n";
+ } else {
+ errs() << "FAILURE : Not Interesting\n";
+ }
+ return Res;
+}
+
+bool increaseGranularity(SmallVector<Chunk> &Chunks) {
+ errs() << "Increasing granularity\n";
+ SmallVector<Chunk> NewChunks;
+ bool SplitOne = false;
+
+ for (auto &C : Chunks) {
+ if (C.Begin == C.End) {
+ NewChunks.push_back(C);
+ } else {
+ int Half = (C.Begin + C.End) / 2;
+ NewChunks.push_back({C.Begin, Half});
+ NewChunks.push_back({Half + 1, C.End});
+ SplitOne = true;
+ }
+ }
+ if (SplitOne) {
+ Chunks = std::move(NewChunks);
+ }
+ return SplitOne;
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+
+ SmallVector<Chunk> CurrChunks;
+ if (DebugCounter::parseChunks(StartChunks, CurrChunks)) {
+ return 1;
+ }
+
+ auto Program = sys::findProgramByName(ReproductionCmd);
+ if (!Program) {
+ errs() << "failed to find command : " << ReproductionCmd << "\n";
+ return 1;
+ }
+ ReproductionCmd.setValue(Program.get());
+
+ errs() << "Input Checking:\n";
+ if (!isStillInteresting(CurrChunks)) {
+ errs() << "starting chunks are not interesting\n";
+ return 1;
+ }
+ if (CurrChunks.size() == 1)
+ increaseGranularity(CurrChunks);
+ if (Pessimist)
+ while (increaseGranularity(CurrChunks))
+ /* empty body */;
+ while (1) {
+ for (int Idx = (CurrChunks.size() - 1); Idx >= 0; Idx--) {
+ if (CurrChunks.size() == 1)
+ break;
+
+ Chunk Testing = CurrChunks[Idx];
+ errs() << "Trying to remove : ";
+ Testing.print(errs());
+ errs() << "\n";
+
+ CurrChunks.erase(CurrChunks.begin() + Idx);
+
+ if (!isStillInteresting(CurrChunks))
+ CurrChunks.insert(CurrChunks.begin() + Idx, Testing);
+ }
+ bool HasSplit = increaseGranularity(CurrChunks);
+ if (!HasSplit)
+ break;
+ }
+
+ errs() << "Minimal Chunks = ";
+ DebugCounter::printChunks(llvm::errs(), simplifyChunksList(CurrChunks));
+ errs() << "\n";
+}
diff --git a/llvm/unittests/Support/DebugCounterTest.cpp b/llvm/unittests/Support/DebugCounterTest.cpp
index e7345b13cc172..820b1ce5ca0d3 100644
--- a/llvm/unittests/Support/DebugCounterTest.cpp
+++ b/llvm/unittests/Support/DebugCounterTest.cpp
@@ -13,28 +13,28 @@
using namespace llvm;
#ifndef NDEBUG
-TEST(DebugCounterTest, CounterCheck) {
+TEST(DebugCounterTest, Basic) {
DEBUG_COUNTER(TestCounter, "test-counter", "Counter used for unit test");
EXPECT_FALSE(DebugCounter::isCounterSet(TestCounter));
-
auto DC = &DebugCounter::instance();
- DC->push_back("test-counter-skip=1");
- DC->push_back("test-counter-count=3");
+ DC->push_back("test-counter=1:3-5:78:79:89:100-102:150");
EXPECT_TRUE(DebugCounter::isCounterSet(TestCounter));
- EXPECT_EQ(0, DebugCounter::getCounterValue(TestCounter));
- EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter));
-
- EXPECT_EQ(1, DebugCounter::getCounterValue(TestCounter));
- EXPECT_TRUE(DebugCounter::shouldExecute(TestCounter));
+ SmallVector<unsigned> Res;
+ for (unsigned Idx = 0; Idx < 200; Idx++) {
+ if (DebugCounter::shouldExecute(TestCounter))
+ Res.push_back(Idx);
+ }
- DebugCounter::setCounterValue(TestCounter, 3);
- EXPECT_TRUE(DebugCounter::shouldExecute(TestCounter));
- EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter));
+ SmallVector<unsigned> Expected = {1, 3, 4, 5, 78, 79, 89, 100, 101, 102, 150};
+ EXPECT_EQ(Expected, Res);
- DebugCounter::setCounterValue(TestCounter, 100);
- EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter));
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ DC->print(OS);
+ EXPECT_TRUE(StringRef(Str).contains("{200,1:3-5:78:79:89:100-102:150}"));
}
+
#endif
More information about the llvm-commits
mailing list