[llvm] [OptBisect] Add support for selecting ranges of passes and refactor DebugCounter to use a shared Range API. (PR #152393)
Yonah Goldberg via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 30 09:43:40 PST 2025
https://github.com/YonahGoldberg updated https://github.com/llvm/llvm-project/pull/152393
>From b5462aca2f0b93d707b806cf91e94f23bd887b5e Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 6 Aug 2025 21:28:33 +0000
Subject: [PATCH 01/49] opt bisect skip
---
llvm/include/llvm/IR/OptBisect.h | 8 +++++++-
llvm/lib/IR/OptBisect.cpp | 10 ++++++++--
llvm/test/Other/opt-bisect-skip.ll | 15 +++++++++++++++
3 files changed, 30 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Other/opt-bisect-skip.ll
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index a8cd56f0b4b0d..d163d403554d0 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -14,6 +14,7 @@
#ifndef LLVM_IR_OPTBISECT_H
#define LLVM_IR_OPTBISECT_H
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
@@ -67,7 +68,11 @@ class LLVM_ABI OptBisect : public OptPassGate {
StringRef IRDescription) const override;
/// isEnabled() should return true before calling shouldRunPass().
- bool isEnabled() const override { return BisectLimit != Disabled; }
+ bool isEnabled() const override { return BisectLimit != Disabled || !BisectSkipNumbers.empty(); }
+
+ void addSkip(int SkipNumber) {
+ BisectSkipNumbers.insert(SkipNumber);
+ }
/// Set the new optimization limit and reset the counter. Passing
/// OptBisect::Disabled disables the limiting.
@@ -81,6 +86,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
private:
int BisectLimit = Disabled;
mutable int LastBisectNum = 0;
+ SmallSet<int, 4> BisectSkipNumbers;
};
/// This class implements a mechanism to disable passes and individual
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 29ca268408265..59639f3b1981d 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -37,6 +37,13 @@ static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
}),
cl::desc("Maximum optimization to perform"));
+static cl::opt<int> OptBisectSkip("opt-bisect-skip", cl::Hidden,
+ cl::init(OptBisect::Disabled), cl::Optional,
+ cl::cb<void, int>([](int PassNum) {
+ getOptBisector().addSkip(PassNum);
+ }),
+ cl::desc("Skip pass at the given index in the optimization pipeline"));
+
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
cl::desc("Show verbose output when opt-bisect-limit is set"), cl::Hidden,
@@ -66,8 +73,7 @@ bool OptBisect::shouldRunPass(StringRef PassName,
assert(isEnabled());
int CurBisectNum = ++LastBisectNum;
- bool ShouldRun = (BisectLimit == -1 || CurBisectNum <= BisectLimit);
- if (OptBisectVerbose)
+ bool ShouldRun = (BisectLimit == -1 || BisectLimit == Disabled || CurBisectNum <= BisectLimit) && !BisectSkipNumbers.contains(CurBisectNum); if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
return ShouldRun;
}
diff --git a/llvm/test/Other/opt-bisect-skip.ll b/llvm/test/Other/opt-bisect-skip.ll
new file mode 100644
index 0000000000000..da94ad6230527
--- /dev/null
+++ b/llvm/test/Other/opt-bisect-skip.ll
@@ -0,0 +1,15 @@
+; Test that verifies functionality for -opt-bisect-skip
+
+; RUN: opt -O1 -opt-bisect-skip=3 -opt-bisect-skip=7 %s 2>&1 | FileCheck %s --check-prefix=CHECK-DISABLE-PASS
+; CHECK-DISABLE-PASS: BISECT: running pass (1) annotation2metadata on [module]
+; CHECK-DISABLE-PASS: BISECT: running pass (2) forceattrs on [module]
+; CHECK-DISABLE-PASS: BISECT: NOT running pass (3) inferattrs on [module]
+; CHECK-DISABLE-PASS: BISECT: running pass (4) lower-expect on foo
+; CHECK-DISABLE-PASS: BISECT: running pass (5) simplifycfg on foo
+; CHECK-DISABLE-PASS: BISECT: running pass (6) sroa on foo
+; CHECK-DISABLE-PASS: BISECT: NOT running pass (7) early-cse on foo
+; CHECK-DISABLE-PASS: BISECT: running pass (8) openmp-opt on [module]
+
+define void @foo() {
+ ret void
+}
\ No newline at end of file
>From 0943e6caceac968f2a71c49a8bec9d0057bf8a99 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 6 Aug 2025 21:28:51 +0000
Subject: [PATCH 02/49] format
---
llvm/include/llvm/IR/OptBisect.h | 8 ++++----
llvm/lib/IR/OptBisect.cpp | 15 ++++++++-------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index d163d403554d0..2bdf6b5572b2c 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -68,12 +68,12 @@ class LLVM_ABI OptBisect : public OptPassGate {
StringRef IRDescription) const override;
/// isEnabled() should return true before calling shouldRunPass().
- bool isEnabled() const override { return BisectLimit != Disabled || !BisectSkipNumbers.empty(); }
-
- void addSkip(int SkipNumber) {
- BisectSkipNumbers.insert(SkipNumber);
+ bool isEnabled() const override {
+ return BisectLimit != Disabled || !BisectSkipNumbers.empty();
}
+ void addSkip(int SkipNumber) { BisectSkipNumbers.insert(SkipNumber); }
+
/// Set the new optimization limit and reset the counter. Passing
/// OptBisect::Disabled disables the limiting.
void setLimit(int Limit) {
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 59639f3b1981d..defb8a98f9716 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -37,12 +37,10 @@ static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
}),
cl::desc("Maximum optimization to perform"));
-static cl::opt<int> OptBisectSkip("opt-bisect-skip", cl::Hidden,
- cl::init(OptBisect::Disabled), cl::Optional,
- cl::cb<void, int>([](int PassNum) {
- getOptBisector().addSkip(PassNum);
- }),
- cl::desc("Skip pass at the given index in the optimization pipeline"));
+static cl::opt<int> OptBisectSkip(
+ "opt-bisect-skip", cl::Hidden, cl::init(OptBisect::Disabled), cl::Optional,
+ cl::cb<void, int>([](int PassNum) { getOptBisector().addSkip(PassNum); }),
+ cl::desc("Skip pass at the given index in the optimization pipeline"));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
@@ -73,7 +71,10 @@ bool OptBisect::shouldRunPass(StringRef PassName,
assert(isEnabled());
int CurBisectNum = ++LastBisectNum;
- bool ShouldRun = (BisectLimit == -1 || BisectLimit == Disabled || CurBisectNum <= BisectLimit) && !BisectSkipNumbers.contains(CurBisectNum); if (OptBisectVerbose)
+ bool ShouldRun = (BisectLimit == -1 || BisectLimit == Disabled ||
+ CurBisectNum <= BisectLimit) &&
+ !BisectSkipNumbers.contains(CurBisectNum);
+ if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
return ShouldRun;
}
>From 8a13ff4f0caf629f1cec9598674fc260b200b528 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 6 Aug 2025 21:36:51 +0000
Subject: [PATCH 03/49] comment
---
llvm/include/llvm/IR/OptBisect.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 2bdf6b5572b2c..ea2c313d39e6c 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -72,6 +72,8 @@ class LLVM_ABI OptBisect : public OptPassGate {
return BisectLimit != Disabled || !BisectSkipNumbers.empty();
}
+ /// Add pass at index SkipNumber to the list of passes to skip
+ /// during bisection.
void addSkip(int SkipNumber) { BisectSkipNumbers.insert(SkipNumber); }
/// Set the new optimization limit and reset the counter. Passing
>From 32f4b1338f66d450b5d29da3639a1fc2e57a55ea Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 6 Aug 2025 21:46:32 +0000
Subject: [PATCH 04/49] newline
---
llvm/test/Other/opt-bisect-skip.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/Other/opt-bisect-skip.ll b/llvm/test/Other/opt-bisect-skip.ll
index da94ad6230527..0f26e5f46f742 100644
--- a/llvm/test/Other/opt-bisect-skip.ll
+++ b/llvm/test/Other/opt-bisect-skip.ll
@@ -12,4 +12,4 @@
define void @foo() {
ret void
-}
\ No newline at end of file
+}
>From 9d7bac56304bae4d6df6ccb68b66f1641fbb552b Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 20 Aug 2025 21:58:07 +0000
Subject: [PATCH 05/49] renaming
---
llvm/include/llvm/IR/OptBisect.h | 4 ++--
llvm/lib/IR/OptBisect.cpp | 8 ++++----
llvm/test/Other/opt-bisect-skip.ll | 15 ---------------
3 files changed, 6 insertions(+), 21 deletions(-)
delete mode 100644 llvm/test/Other/opt-bisect-skip.ll
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index ea2c313d39e6c..24e00934585bd 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -72,9 +72,9 @@ class LLVM_ABI OptBisect : public OptPassGate {
return BisectLimit != Disabled || !BisectSkipNumbers.empty();
}
- /// Add pass at index SkipNumber to the list of passes to skip
+ /// Add pass at index Index to the list of passes to skip
/// during bisection.
- void addSkip(int SkipNumber) { BisectSkipNumbers.insert(SkipNumber); }
+ void disablePassAtIndex(int Index) { BisectSkipNumbers.insert(Index); }
/// Set the new optimization limit and reset the counter. Passing
/// OptBisect::Disabled disables the limiting.
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index defb8a98f9716..8850e8f0c32a6 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -37,10 +37,10 @@ static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
}),
cl::desc("Maximum optimization to perform"));
-static cl::opt<int> OptBisectSkip(
- "opt-bisect-skip", cl::Hidden, cl::init(OptBisect::Disabled), cl::Optional,
- cl::cb<void, int>([](int PassNum) { getOptBisector().addSkip(PassNum); }),
- cl::desc("Skip pass at the given index in the optimization pipeline"));
+static cl::list<int> OptDisableIndices(
+ "opt-disable-indices", cl::Hidden, cl::CommaSeparated, cl::Optional,
+ cl::cb<void, int>([](int Index) { getOptBisector().disablePassAtIndex(Index); }),
+ cl::desc("Disable passes at the given indices in the optimization pipeline (comma-separated list)"));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
diff --git a/llvm/test/Other/opt-bisect-skip.ll b/llvm/test/Other/opt-bisect-skip.ll
deleted file mode 100644
index 0f26e5f46f742..0000000000000
--- a/llvm/test/Other/opt-bisect-skip.ll
+++ /dev/null
@@ -1,15 +0,0 @@
-; Test that verifies functionality for -opt-bisect-skip
-
-; RUN: opt -O1 -opt-bisect-skip=3 -opt-bisect-skip=7 %s 2>&1 | FileCheck %s --check-prefix=CHECK-DISABLE-PASS
-; CHECK-DISABLE-PASS: BISECT: running pass (1) annotation2metadata on [module]
-; CHECK-DISABLE-PASS: BISECT: running pass (2) forceattrs on [module]
-; CHECK-DISABLE-PASS: BISECT: NOT running pass (3) inferattrs on [module]
-; CHECK-DISABLE-PASS: BISECT: running pass (4) lower-expect on foo
-; CHECK-DISABLE-PASS: BISECT: running pass (5) simplifycfg on foo
-; CHECK-DISABLE-PASS: BISECT: running pass (6) sroa on foo
-; CHECK-DISABLE-PASS: BISECT: NOT running pass (7) early-cse on foo
-; CHECK-DISABLE-PASS: BISECT: running pass (8) openmp-opt on [module]
-
-define void @foo() {
- ret void
-}
>From d7a19bfa4cd6058a2cfe86c5b6ac8bffbe5738e3 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 20 Aug 2025 22:03:17 +0000
Subject: [PATCH 06/49] format
---
llvm/lib/IR/OptBisect.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 8850e8f0c32a6..e5d64a02455ac 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -37,10 +37,13 @@ static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
}),
cl::desc("Maximum optimization to perform"));
-static cl::list<int> OptDisableIndices(
- "opt-disable-indices", cl::Hidden, cl::CommaSeparated, cl::Optional,
- cl::cb<void, int>([](int Index) { getOptBisector().disablePassAtIndex(Index); }),
- cl::desc("Disable passes at the given indices in the optimization pipeline (comma-separated list)"));
+static cl::list<int>
+ OptDisableIndices("opt-disable-indices", cl::Hidden, cl::CommaSeparated,
+ cl::Optional, cl::cb<void, int>([](int Index) {
+ getOptBisector().disablePassAtIndex(Index);
+ }),
+ cl::desc("Disable passes at the given indices in the "
+ "optimization pipeline (comma-separated list)"));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
>From 8345360f5076a58dd492bcd778c55b2ae4a28496 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 04:33:27 +0000
Subject: [PATCH 07/49] range support
---
llvm/include/llvm/IR/OptBisect.h | 40 +--
llvm/include/llvm/Support/DebugCounter.h | 29 ++-
llvm/include/llvm/Support/Range.h | 80 ++++++
llvm/lib/IR/OptBisect.cpp | 52 ++--
llvm/lib/Support/CMakeLists.txt | 1 +
llvm/lib/Support/DebugCounter.cpp | 79 +-----
llvm/lib/Support/Range.cpp | 140 +++++++++++
llvm/test/Other/debugcounter-multi-ranges.ll | 38 +++
llvm/test/Other/opt-bisect-ranges.ll | 35 +++
llvm/test/Other/opt-disable-indices.ll | 15 ++
.../reduce-chunk-list/reduce-chunk-list.cpp | 47 ++--
llvm/unittests/Support/CMakeLists.txt | 1 +
llvm/unittests/Support/RangeTest.cpp | 233 ++++++++++++++++++
13 files changed, 646 insertions(+), 144 deletions(-)
create mode 100644 llvm/include/llvm/Support/Range.h
create mode 100644 llvm/lib/Support/Range.cpp
create mode 100644 llvm/test/Other/debugcounter-multi-ranges.ll
create mode 100644 llvm/test/Other/opt-bisect-ranges.ll
create mode 100644 llvm/test/Other/opt-disable-indices.ll
create mode 100644 llvm/unittests/Support/RangeTest.cpp
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 24e00934585bd..f249a52494985 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -14,11 +14,12 @@
#ifndef LLVM_IR_OPTBISECT_H
#define LLVM_IR_OPTBISECT_H
-#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
-#include <limits>
+#include "llvm/Support/Range.h"
namespace llvm {
@@ -41,7 +42,7 @@ class OptPassGate {
/// This class implements a mechanism to disable passes and individual
/// optimizations at compile time based on a command line option
-/// (-opt-bisect-limit) in order to perform a bisecting search for
+/// (-opt-bisect) in order to perform a bisecting search for
/// optimization-related problems.
class LLVM_ABI OptBisect : public OptPassGate {
public:
@@ -54,12 +55,12 @@ class LLVM_ABI OptBisect : public OptPassGate {
~OptBisect() override = default;
- /// Checks the bisect limit to determine if the specified pass should run.
+ /// Checks the bisect ranges to determine if the specified pass should run.
///
/// The method prints the name of the pass, its assigned bisect number, and
/// whether or not the pass will be executed. It returns true if the pass
- /// should run, i.e. if the bisect limit is set to -1 or has not yet been
- /// exceeded.
+ /// should run, i.e. if no ranges are specified or the current pass number
+ /// falls within one of the specified ranges.
///
/// Most passes should not call this routine directly. Instead, it is called
/// through helper routines provided by the base classes of the pass. For
@@ -68,27 +69,28 @@ class LLVM_ABI OptBisect : public OptPassGate {
StringRef IRDescription) const override;
/// isEnabled() should return true before calling shouldRunPass().
- bool isEnabled() const override {
- return BisectLimit != Disabled || !BisectSkipNumbers.empty();
- }
+ bool isEnabled() const override { return !BisectRanges.empty(); }
- /// Add pass at index Index to the list of passes to skip
- /// during bisection.
- void disablePassAtIndex(int Index) { BisectSkipNumbers.insert(Index); }
+ /// Parse range specification and set the ranges for bisection.
+ /// Range format: "1-10,20-30,45" (runs passes 1-10, 20-30, and 45)
+ /// Returns true on parsing error.
+ bool parseRanges(StringRef RangeStr);
- /// Set the new optimization limit and reset the counter. Passing
- /// OptBisect::Disabled disables the limiting.
- void setLimit(int Limit) {
- BisectLimit = Limit;
+ /// Set ranges programmatically (for testing or other uses).
+ void setRanges(ArrayRef<Range> Ranges) {
+ BisectRanges.assign(Ranges.begin(), Ranges.end());
LastBisectNum = 0;
}
- static constexpr int Disabled = std::numeric_limits<int>::max();
+ /// Clear all ranges, effectively disabling bisection.
+ void clearRanges() {
+ BisectRanges.clear();
+ LastBisectNum = 0;
+ }
private:
- int BisectLimit = Disabled;
mutable int LastBisectNum = 0;
- SmallSet<int, 4> BisectSkipNumbers;
+ RangeUtils::RangeList BisectRanges;
};
/// This class implements a mechanism to disable passes and individual
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index 979d6b8e62f23..72338f7633938 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -48,6 +48,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Range.h"
#include <string>
namespace llvm {
@@ -56,12 +57,8 @@ class raw_ostream;
class DebugCounter {
public:
- struct Chunk {
- int64_t Begin;
- int64_t End;
- LLVM_ABI void print(llvm::raw_ostream &OS);
- bool contains(int64_t Idx) const { return Idx >= Begin && Idx <= End; }
- };
+ // For backward compatibility, alias Range as Chunk
+ using Chunk = Range;
/// Struct to store counter info.
class CounterInfo {
@@ -86,7 +83,7 @@ class DebugCounter {
}
};
- LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<Chunk>);
+ LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<Range> Ranges);
/// Return true on parsing error and print the error message on the
/// llvm::errs()
@@ -170,8 +167,26 @@ class DebugCounter {
}
protected:
+<<<<<<< HEAD
void addCounter(CounterInfo *Info) { Counters[Info->Name] = Info; }
bool handleCounterIncrement(CounterInfo &Info);
+=======
+ unsigned addCounter(const std::string &Name, const std::string &Desc) {
+ unsigned Result = RegisteredCounters.insert(Name);
+ auto &C = Counters[Result];
+ C = {};
+ C.Desc = Desc;
+ return Result;
+ }
+ // Struct to store counter info.
+ struct CounterInfo {
+ int64_t Count = 0;
+ uint64_t CurrChunkIdx = 0;
+ bool IsSet = false;
+ std::string Desc;
+ SmallVector<Range> Chunks;
+ };
+>>>>>>> 0242e6f869bd (range support)
MapVector<StringRef, CounterInfo *> Counters;
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
new file mode 100644
index 0000000000000..c05cced7c7912
--- /dev/null
+++ b/llvm/include/llvm/Support/Range.h
@@ -0,0 +1,80 @@
+//===- llvm/Support/Range.h - Range parsing utility -----------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides utilities for parsing range specifications like "1-10,20-30,45"
+// which are commonly used in debugging and bisection tools.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RANGE_H
+#define LLVM_SUPPORT_RANGE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+
+namespace llvm {
+class raw_ostream;
+} // end namespace llvm
+
+namespace llvm {
+
+/// Represents a range of integers [Begin, End] (inclusive on both ends)
+struct Range {
+ int64_t Begin;
+ int64_t End;
+
+ Range(int64_t Begin, int64_t End) : Begin(Begin), End(End) {}
+ Range(int64_t Single) : Begin(Single), End(Single) {}
+
+ /// Check if the given value is within this range (inclusive)
+ bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
+
+ /// Check if this range overlaps with another range
+ bool overlaps(const Range &Other) const {
+ return Begin <= Other.End && End >= Other.Begin;
+ }
+
+ /// Get the size of this range
+ int64_t size() const { return End - Begin + 1; }
+
+ bool operator==(const Range &Other) const {
+ return Begin == Other.Begin && End == Other.End;
+ }
+};
+
+/// Utility class for parsing and managing range specifications
+class RangeUtils {
+public:
+ using RangeList = SmallVector<Range, 8>;
+
+ /// Parse a range specification string like "1-10,20-30,45" or "1-10:20-30:45"
+ /// Returns true on error, false on success
+ /// \param RangeStr The string to parse
+ /// \param Ranges Output list of parsed ranges
+ /// \param Separator The separator character to use (',' or ':')
+ static bool parseRanges(StringRef RangeStr, RangeList &Ranges, char Separator = ',');
+
+ /// Check if a value is contained in any of the ranges
+ static bool contains(const RangeList &Ranges, int64_t Value);
+
+ /// Convert ranges back to string representation for debugging
+ static std::string rangesToString(const RangeList &Ranges, char Separator = ',');
+
+ /// Print ranges to output stream (DebugCounter-compatible)
+ static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges);
+
+ /// Merge adjacent/consecutive ranges into single ranges
+ /// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10]
+ static RangeList mergeAdjacentRanges(ArrayRef<Range> Ranges);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_RANGE_H
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index e5d64a02455ac..ad0dd8930ecc1 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -13,10 +13,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/OptBisect.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Range.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <cstdlib>
using namespace llvm;
@@ -31,19 +34,34 @@ static OptDisable &getOptDisabler() {
}
static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
- cl::init(OptBisect::Disabled), cl::Optional,
+ cl::init(-1), cl::Optional,
cl::cb<void, int>([](int Limit) {
- getOptBisector().setLimit(Limit);
+ if (Limit == -1) {
+ // -1 means run all passes, which is equivalent to no ranges
+ getOptBisector().clearRanges();
+ } else if (Limit > 0) {
+ // Convert limit to range 1-Limit
+ std::string RangeStr = "1-" + llvm::utostr(Limit);
+ if (getOptBisector().parseRanges(RangeStr)) {
+ errs() << "Error: Invalid limit for -opt-bisect-limit: "
+ << Limit << "\n";
+ exit(1);
+ }
+ }
}),
- cl::desc("Maximum optimization to perform"));
-
-static cl::list<int>
- OptDisableIndices("opt-disable-indices", cl::Hidden, cl::CommaSeparated,
- cl::Optional, cl::cb<void, int>([](int Index) {
- getOptBisector().disablePassAtIndex(Index);
- }),
- cl::desc("Disable passes at the given indices in the "
- "optimization pipeline (comma-separated list)"));
+ cl::desc("Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
+
+static cl::opt<std::string> OptBisectRanges(
+ "opt-bisect", cl::Hidden, cl::Optional,
+ cl::cb<void, const std::string &>([](const std::string &RangeStr) {
+ if (getOptBisector().parseRanges(RangeStr)) {
+ errs() << "Error: Invalid range specification for -opt-bisect: "
+ << RangeStr << "\n";
+ exit(1);
+ }
+ }),
+ cl::desc("Run optimization passes only for the specified ranges. "
+ "Format: '1-10,20-30,45' (runs passes 1-10, 20-30, and 45)"));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
@@ -69,14 +87,20 @@ static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
<< " on " << TargetDesc << '\n';
}
+bool OptBisect::parseRanges(StringRef RangeStr) {
+ LastBisectNum = 0;
+ return RangeUtils::parseRanges(RangeStr, BisectRanges);
+}
+
bool OptBisect::shouldRunPass(StringRef PassName,
StringRef IRDescription) const {
assert(isEnabled());
int CurBisectNum = ++LastBisectNum;
- bool ShouldRun = (BisectLimit == -1 || BisectLimit == Disabled ||
- CurBisectNum <= BisectLimit) &&
- !BisectSkipNumbers.contains(CurBisectNum);
+
+ // Check if current pass number falls within any of the specified ranges
+ bool ShouldRun = RangeUtils::contains(BisectRanges, CurBisectNum);
+
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
return ShouldRun;
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 1c397e8c0b766..14776ed1f7430 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -236,6 +236,7 @@ add_llvm_component_library(LLVMSupport
PluginLoader.cpp
PrettyStackTrace.cpp
RandomNumberGenerator.cpp
+ Range.cpp
Regex.cpp
RewriteBuffer.cpp
RewriteRope.cpp
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 6c69c884a684d..db5682be16341 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -10,77 +10,8 @@ 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;
+void DebugCounter::printChunks(raw_ostream &OS, ArrayRef<Range> Ranges) {
+ RangeUtils::printRanges(OS, Ranges);
}
} // namespace llvm
@@ -193,11 +124,13 @@ void DebugCounter::push_back(const std::string &Val) {
return;
}
StringRef CounterName = CounterPair.first;
- SmallVector<Chunk> Chunks;
+ RangeUtils::RangeList TempRanges;
+ SmallVector<Range> Chunks;
- if (parseChunks(CounterPair.second, Chunks)) {
+ if (RangeUtils::parseRanges(CounterPair.second, TempRanges, ':')) {
return;
}
+ Chunks.assign(TempRanges.begin(), TempRanges.end());
CounterInfo *Counter = getCounterInfo(CounterName);
if (!Counter) {
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
new file mode 100644
index 0000000000000..4b1952ab8e202
--- /dev/null
+++ b/llvm/lib/Support/Range.cpp
@@ -0,0 +1,140 @@
+//===- llvm/Support/Range.cpp - Range parsing utility ---------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Range.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include <sstream>
+
+using namespace llvm;
+
+bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
+ Ranges.clear();
+
+ if (Str.empty())
+ return false;
+
+ // Split by the specified separator
+ SmallVector<StringRef, 8> Parts;
+ Str.split(Parts, Separator, -1, false);
+
+ // Regex to match either single number or range "num1-num2"
+ Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
+
+ for (StringRef Part : Parts) {
+ Part = Part.trim();
+ if (Part.empty())
+ continue;
+
+ SmallVector<StringRef, 4> Matches;
+ if (!RangeRegex.match(Part, &Matches)) {
+ errs() << "Invalid range format: '" << Part << "'\n";
+ return true;
+ }
+
+ int64_t Begin, End;
+ if (Matches[1].getAsInteger(10, Begin)) {
+ errs() << "Failed to parse number: '" << Matches[1] << "'\n";
+ return true;
+ }
+
+ if (!Matches[3].empty()) {
+ // Range format "begin-end"
+ if (Matches[3].getAsInteger(10, End)) {
+ errs() << "Failed to parse number: '" << Matches[3] << "'\n";
+ return true;
+ }
+ if (Begin >= End) {
+ errs() << "Invalid range: " << Begin << " >= " << End << "\n";
+ return true;
+ }
+ } else {
+ // Single number
+ End = Begin;
+ }
+
+ // Check ordering constraint (ranges must be in increasing order)
+ if (!Ranges.empty() && Begin <= Ranges.back().End) {
+ errs() << "Expected ranges to be in increasing order: " << Begin
+ << " <= " << Ranges.back().End << "\n";
+ return true;
+ }
+
+ Ranges.push_back(Range(Begin, End));
+ }
+
+ return false;
+}
+
+bool RangeUtils::contains(const RangeList &Ranges, int64_t Value) {
+ for (const Range &R : Ranges) {
+ if (R.contains(Value))
+ return true;
+ }
+ return false;
+}
+
+
+
+std::string RangeUtils::rangesToString(const RangeList &Ranges, char Separator) {
+ std::ostringstream OS;
+ for (size_t I = 0; I < Ranges.size(); ++I) {
+ if (I > 0)
+ OS << Separator;
+ const Range &R = Ranges[I];
+ if (R.Begin == R.End) {
+ OS << R.Begin;
+ } else {
+ OS << R.Begin << "-" << R.End;
+ }
+ }
+ return OS.str();
+}
+
+void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges) {
+ if (Ranges.empty()) {
+ OS << "empty";
+ } else {
+ bool IsFirst = true;
+ for (const Range &R : Ranges) {
+ if (!IsFirst)
+ OS << ':';
+ else
+ IsFirst = false;
+
+ if (R.Begin == R.End)
+ OS << R.Begin;
+ else
+ OS << R.Begin << "-" << R.End;
+ }
+ }
+}
+
+RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
+ if (Ranges.empty())
+ return {};
+
+ RangeList Result;
+ Result.push_back(Ranges[0]);
+
+ for (size_t I = 1; I < Ranges.size(); ++I) {
+ const Range &Current = Ranges[I];
+ Range &Last = Result.back();
+
+ // Check if current range is adjacent to the last merged range
+ if (Current.Begin == Last.End + 1) {
+ // Merge by extending the end of the last range
+ Last.End = Current.End;
+ } else {
+ // Not adjacent, add as separate range
+ Result.push_back(Current);
+ }
+ }
+
+ return Result;
+}
diff --git a/llvm/test/Other/debugcounter-multi-ranges.ll b/llvm/test/Other/debugcounter-multi-ranges.ll
new file mode 100644
index 0000000000000..30cdbc6e40c0b
--- /dev/null
+++ b/llvm/test/Other/debugcounter-multi-ranges.ll
@@ -0,0 +1,38 @@
+; REQUIRES: asserts
+; Test debug counter with multiple ranges using colon separators
+; (DebugCounter uses colon separators to avoid conflicts with cl::CommaSeparated)
+
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1:3:5 < %s | FileCheck %s --check-prefix=CHECK-COLON
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2:4:6-7 < %s | FileCheck %s --check-prefix=CHECK-MIXED-COLON
+
+; Test that with debug counters on, we can selectively apply transformations
+; using different range syntaxes. All variants should produce the same result.
+
+; Original function has 8 dead instructions that DCE can eliminate
+define void @test() {
+ %dead1 = add i32 1, 2
+ %dead2 = add i32 3, 4
+ %dead3 = add i32 5, 6
+ %dead4 = add i32 7, 8
+ %dead5 = add i32 9, 10
+ %dead6 = add i32 11, 12
+ %dead7 = add i32 13, 14
+ %dead8 = add i32 15, 16
+ ret void
+}
+
+; Test colon separator: apply transformations 1, 3, 5 (eliminate dead2, dead4, dead6)
+; CHECK-COLON-LABEL: @test
+; CHECK-COLON-NEXT: %dead1 = add i32 1, 2
+; CHECK-COLON-NEXT: %dead3 = add i32 5, 6
+; CHECK-COLON-NEXT: %dead5 = add i32 9, 10
+; CHECK-COLON-NEXT: %dead7 = add i32 13, 14
+; CHECK-COLON-NEXT: %dead8 = add i32 15, 16
+; CHECK-COLON-NEXT: ret void
+
+; Test mixed ranges with colon: apply transformations 1-2, 4, 6-7 (eliminate dead2, dead3, dead5, dead7, dead8)
+; CHECK-MIXED-COLON-LABEL: @test
+; CHECK-MIXED-COLON-NEXT: %dead1 = add i32 1, 2
+; CHECK-MIXED-COLON-NEXT: %dead4 = add i32 7, 8
+; CHECK-MIXED-COLON-NEXT: %dead6 = add i32 11, 12
+; CHECK-MIXED-COLON-NEXT: ret void
diff --git a/llvm/test/Other/opt-bisect-ranges.ll b/llvm/test/Other/opt-bisect-ranges.ll
new file mode 100644
index 0000000000000..145cf169ca370
--- /dev/null
+++ b/llvm/test/Other/opt-bisect-ranges.ll
@@ -0,0 +1,35 @@
+; Test that verifies functionality for -opt-bisect with range specifications
+
+; Test basic range functionality: run passes 1-3 and 7-8
+; RUN: opt -O1 -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-RANGES
+; CHECK-RANGES: BISECT: running pass (1) annotation2metadata on [module]
+; CHECK-RANGES: BISECT: running pass (2) forceattrs on [module]
+; CHECK-RANGES: BISECT: running pass (3) inferattrs on [module]
+; CHECK-RANGES: BISECT: NOT running pass (4) lower-expect on foo
+; CHECK-RANGES: BISECT: NOT running pass (5) simplifycfg on foo
+; CHECK-RANGES: BISECT: NOT running pass (6) sroa on foo
+; CHECK-RANGES: BISECT: running pass (7) early-cse on foo
+; CHECK-RANGES: BISECT: running pass (8) openmp-opt on [module]
+
+; Test single pass selection: run only pass 5
+; RUN: opt -O1 -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE
+; CHECK-SINGLE: BISECT: NOT running pass (1) annotation2metadata on [module]
+; CHECK-SINGLE: BISECT: NOT running pass (2) forceattrs on [module]
+; CHECK-SINGLE: BISECT: NOT running pass (3) inferattrs on [module]
+; CHECK-SINGLE: BISECT: NOT running pass (4) lower-expect on foo
+; CHECK-SINGLE: BISECT: running pass (5) simplifycfg on foo
+; CHECK-SINGLE: BISECT: NOT running pass (6) sroa on foo
+
+; Test backward compatibility: -opt-bisect-limit=3 should be equivalent to -opt-bisect=1-3
+; RUN: opt -O1 -opt-bisect-limit=3 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIMIT
+; CHECK-LIMIT: BISECT: running pass (1) annotation2metadata on [module]
+; CHECK-LIMIT: BISECT: running pass (2) forceattrs on [module]
+; CHECK-LIMIT: BISECT: running pass (3) inferattrs on [module]
+; CHECK-LIMIT: BISECT: NOT running pass (4) lower-expect on foo
+; CHECK-LIMIT: BISECT: NOT running pass (5) simplifycfg on foo
+
+define void @foo() {
+ ret void
+}
+
+
diff --git a/llvm/test/Other/opt-disable-indices.ll b/llvm/test/Other/opt-disable-indices.ll
new file mode 100644
index 0000000000000..52c2b5b1c4ffa
--- /dev/null
+++ b/llvm/test/Other/opt-disable-indices.ll
@@ -0,0 +1,15 @@
+; Test that verifies functionality for -opt-disable-indices
+
+; RUN: opt -O1 -opt-disable-indices=3,7 %s 2>&1 | FileCheck %s --check-prefix=CHECK-DISABLE-PASS
+; CHECK-DISABLE-PASS: BISECT: running pass (1) annotation2metadata on [module]
+; CHECK-DISABLE-PASS: BISECT: running pass (2) forceattrs on [module]
+; CHECK-DISABLE-PASS: BISECT: NOT running pass (3) inferattrs on [module]
+; CHECK-DISABLE-PASS: BISECT: running pass (4) lower-expect on foo
+; CHECK-DISABLE-PASS: BISECT: running pass (5) simplifycfg on foo
+; CHECK-DISABLE-PASS: BISECT: running pass (6) sroa on foo
+; CHECK-DISABLE-PASS: BISECT: NOT running pass (7) early-cse on foo
+; CHECK-DISABLE-PASS: BISECT: running pass (8) openmp-opt on [module]
+
+define void @foo() {
+ ret void
+}
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index dc99859b516db..687367b351a6c 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -11,10 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/Range.h"
using namespace llvm;
@@ -24,29 +23,15 @@ static cl::opt<std::string> StartChunks(cl::Positional, cl::Required);
static 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);
+bool isStillInteresting(ArrayRef<Range> Chunks) {
+ RangeUtils::RangeList SimpleChunks = RangeUtils::mergeAdjacentRanges(Chunks);
std::string ChunkStr;
{
raw_string_ostream OS(ChunkStr);
- DebugCounter::printChunks(OS, SimpleChunks);
+ RangeUtils::printRanges(OS, SimpleChunks);
}
errs() << "Checking with: " << ChunkStr << "\n";
@@ -73,18 +58,18 @@ bool isStillInteresting(ArrayRef<Chunk> Chunks) {
return Res;
}
-bool increaseGranularity(SmallVector<Chunk> &Chunks) {
+bool increaseGranularity(RangeUtils::RangeList &Chunks) {
errs() << "Increasing granularity\n";
- SmallVector<Chunk> NewChunks;
+ RangeUtils::RangeList 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});
+ int64_t Half = (C.Begin + C.End) / 2;
+ NewChunks.push_back(Range(C.Begin, Half));
+ NewChunks.push_back(Range(Half + 1, C.End));
SplitOne = true;
}
}
@@ -99,10 +84,9 @@ bool increaseGranularity(SmallVector<Chunk> &Chunks) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
- SmallVector<Chunk> CurrChunks;
- if (DebugCounter::parseChunks(StartChunks, CurrChunks)) {
+ RangeUtils::RangeList CurrChunks;
+ if (RangeUtils::parseRanges(StartChunks, CurrChunks, ','))
return 1;
- }
auto Program = sys::findProgramByName(ReproductionCmd);
if (!Program) {
@@ -126,9 +110,10 @@ int main(int argc, char **argv) {
if (CurrChunks.size() == 1)
break;
- Chunk Testing = CurrChunks[Idx];
- errs() << "Trying to remove : ";
- Testing.print(errs());
+ Range Testing = CurrChunks[Idx];
+ errs() << "Trying to remove : " << Testing.Begin;
+ if (Testing.Begin != Testing.End)
+ errs() << "-" << Testing.End;
errs() << "\n";
CurrChunks.erase(CurrChunks.begin() + Idx);
@@ -142,6 +127,6 @@ int main(int argc, char **argv) {
}
errs() << "Minimal Chunks = ";
- DebugCounter::printChunks(llvm::errs(), simplifyChunksList(CurrChunks));
+ RangeUtils::printRanges(llvm::errs(), RangeUtils::mergeAdjacentRanges(CurrChunks));
errs() << "\n";
}
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 21f10eb610f11..db60a9ea5e9f0 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -76,6 +76,7 @@ add_llvm_unittest(SupportTests
ProcessTest.cpp
ProgramTest.cpp
ProgramStackTest.cpp
+ RangeTest.cpp
RecyclerTest.cpp
RegexTest.cpp
ReverseIterationTest.cpp
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
new file mode 100644
index 0000000000000..d4a91327bd992
--- /dev/null
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -0,0 +1,233 @@
+//===- llvm/unittests/Support/RangeTest.cpp - Range tests ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Range.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(RangeTest, BasicRange) {
+ Range R(5, 10);
+ EXPECT_EQ(R.Begin, 5);
+ EXPECT_EQ(R.End, 10);
+ EXPECT_TRUE(R.contains(5));
+ EXPECT_TRUE(R.contains(7));
+ EXPECT_TRUE(R.contains(10));
+ EXPECT_FALSE(R.contains(4));
+ EXPECT_FALSE(R.contains(11));
+}
+
+TEST(RangeTest, SingleValueRange) {
+ Range R(42);
+ EXPECT_EQ(R.Begin, 42);
+ EXPECT_EQ(R.End, 42);
+ EXPECT_TRUE(R.contains(42));
+ EXPECT_FALSE(R.contains(41));
+ EXPECT_FALSE(R.contains(43));
+}
+
+TEST(RangeTest, RangeOverlaps) {
+ Range R1(1, 5);
+ Range R2(3, 8);
+ Range R3(6, 10);
+ Range R4(11, 15);
+
+ EXPECT_TRUE(R1.overlaps(R2));
+ EXPECT_TRUE(R2.overlaps(R1));
+ EXPECT_TRUE(R2.overlaps(R3));
+ EXPECT_FALSE(R1.overlaps(R3));
+ EXPECT_FALSE(R1.overlaps(R4));
+ EXPECT_FALSE(R3.overlaps(R4));
+}
+
+TEST(RangeUtilsTest, ParseSingleNumber) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("42", Ranges));
+ EXPECT_EQ(Ranges.size(), 1U);
+ EXPECT_EQ(Ranges[0].Begin, 42);
+ EXPECT_EQ(Ranges[0].End, 42);
+}
+
+TEST(RangeUtilsTest, ParseSingleRange) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("10-20", Ranges));
+ EXPECT_EQ(Ranges.size(), 1U);
+ EXPECT_EQ(Ranges[0].Begin, 10);
+ EXPECT_EQ(Ranges[0].End, 20);
+}
+
+TEST(RangeUtilsTest, ParseMultipleRanges) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ EXPECT_EQ(Ranges.size(), 3U);
+
+ // Ranges are in input order (DebugCounter style)
+ EXPECT_EQ(Ranges[0].Begin, 1);
+ EXPECT_EQ(Ranges[0].End, 5);
+ EXPECT_EQ(Ranges[1].Begin, 10);
+ EXPECT_EQ(Ranges[1].End, 10);
+ EXPECT_EQ(Ranges[2].Begin, 15);
+ EXPECT_EQ(Ranges[2].End, 20);
+}
+
+TEST(RangeUtilsTest, ParseColonSeparated) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5:10:15-20", Ranges));
+ EXPECT_EQ(Ranges.size(), 3U);
+ EXPECT_EQ(Ranges[0].Begin, 1);
+ EXPECT_EQ(Ranges[0].End, 5);
+ EXPECT_EQ(Ranges[1].Begin, 10);
+ EXPECT_EQ(Ranges[1].End, 10);
+ EXPECT_EQ(Ranges[2].Begin, 15);
+ EXPECT_EQ(Ranges[2].End, 20);
+}
+
+TEST(RangeUtilsTest, ParseEmptyString) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("", Ranges));
+ EXPECT_TRUE(Ranges.empty());
+}
+
+TEST(RangeUtilsTest, ParseInvalidRanges) {
+ RangeUtils::RangeList Ranges;
+
+ // Invalid number
+ EXPECT_TRUE(RangeUtils::parseRanges("abc", Ranges));
+
+ // Invalid range (begin > end)
+ EXPECT_TRUE(RangeUtils::parseRanges("10-5", Ranges));
+
+ // Out of order ranges (DebugCounter constraint)
+ EXPECT_TRUE(RangeUtils::parseRanges("10,5", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping
+}
+
+TEST(RangeUtilsTest, Contains) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 1));
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 3));
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 5));
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 10));
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 15));
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 18));
+ EXPECT_TRUE(RangeUtils::contains(Ranges, 20));
+
+ EXPECT_FALSE(RangeUtils::contains(Ranges, 6));
+ EXPECT_FALSE(RangeUtils::contains(Ranges, 9));
+ EXPECT_FALSE(RangeUtils::contains(Ranges, 11));
+ EXPECT_FALSE(RangeUtils::contains(Ranges, 14));
+ EXPECT_FALSE(RangeUtils::contains(Ranges, 21));
+}
+
+TEST(RangeUtilsTest, RangesToString) {
+ RangeUtils::RangeList Ranges;
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+
+ std::string Result = RangeUtils::rangesToString(Ranges);
+ EXPECT_EQ(Result, "1-5,10,15-20");
+}
+
+TEST(RangeUtilsTest, SeparatorParameter) {
+ RangeUtils::RangeList ColonRanges, CommaRanges;
+
+ // Test explicit separator parameters
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5:10:15-20", ColonRanges, ':'));
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", CommaRanges, ','));
+
+ EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
+ for (size_t I = 0; I < ColonRanges.size(); ++I) {
+ EXPECT_EQ(ColonRanges[I].Begin, CommaRanges[I].Begin);
+ EXPECT_EQ(ColonRanges[I].End, CommaRanges[I].End);
+ }
+
+ // Test that both work with contains()
+ EXPECT_TRUE(RangeUtils::contains(ColonRanges, 3));
+ EXPECT_TRUE(RangeUtils::contains(CommaRanges, 3));
+ EXPECT_TRUE(RangeUtils::contains(ColonRanges, 10));
+ EXPECT_TRUE(RangeUtils::contains(CommaRanges, 10));
+ EXPECT_TRUE(RangeUtils::contains(ColonRanges, 18));
+ EXPECT_TRUE(RangeUtils::contains(CommaRanges, 18));
+
+ EXPECT_FALSE(RangeUtils::contains(ColonRanges, 8));
+ EXPECT_FALSE(RangeUtils::contains(CommaRanges, 8));
+}
+
+TEST(RangeUtilsTest, DefaultCommaSeparator) {
+ RangeUtils::RangeList Ranges;
+
+ // Test that comma is the default separator
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ EXPECT_EQ(Ranges.size(), 3U);
+ EXPECT_EQ(Ranges[0].Begin, 1);
+ EXPECT_EQ(Ranges[0].End, 5);
+ EXPECT_EQ(Ranges[1].Begin, 10);
+ EXPECT_EQ(Ranges[1].End, 10);
+ EXPECT_EQ(Ranges[2].Begin, 15);
+ EXPECT_EQ(Ranges[2].End, 20);
+}
+
+TEST(RangeTest, MergeAdjacentRanges) {
+ RangeUtils::RangeList Input, Expected, Result;
+
+ // Empty input
+ Result = RangeUtils::mergeAdjacentRanges(Input);
+ EXPECT_TRUE(Result.empty());
+
+ // Single range - no change
+ Input.push_back(Range(5, 10));
+ Expected.push_back(Range(5, 10));
+ Result = RangeUtils::mergeAdjacentRanges(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Adjacent ranges should merge
+ Input.clear();
+ Expected.clear();
+ Input.push_back(Range(1, 3));
+ Input.push_back(Range(4, 6));
+ Input.push_back(Range(7, 9));
+ Expected.push_back(Range(1, 9));
+ Result = RangeUtils::mergeAdjacentRanges(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Non-adjacent ranges should not merge
+ Input.clear();
+ Expected.clear();
+ Input.push_back(Range(1, 3));
+ Input.push_back(Range(5, 7)); // Gap between 3 and 5
+ Input.push_back(Range(10, 12)); // Gap between 7 and 10
+ Expected.push_back(Range(1, 3));
+ Expected.push_back(Range(5, 7));
+ Expected.push_back(Range(10, 12));
+ Result = RangeUtils::mergeAdjacentRanges(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Mixed adjacent and non-adjacent
+ Input.clear();
+ Expected.clear();
+ Input.push_back(Range(1, 3));
+ Input.push_back(Range(4, 6)); // Adjacent to first
+ Input.push_back(Range(8, 10)); // Gap
+ Input.push_back(Range(11, 13)); // Adjacent to third
+ Input.push_back(Range(14, 16)); // Adjacent to fourth
+ Expected.push_back(Range(1, 6)); // Merged 1-3 and 4-6
+ Expected.push_back(Range(8, 16)); // Merged 8-10, 11-13, 14-16
+ Result = RangeUtils::mergeAdjacentRanges(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Single numbers that are adjacent
+ Input.clear();
+ Expected.clear();
+ Input.push_back(Range(5));
+ Input.push_back(Range(6));
+ Input.push_back(Range(7));
+ Expected.push_back(Range(5, 7));
+ Result = RangeUtils::mergeAdjacentRanges(Input);
+ EXPECT_EQ(Expected, Result);
+}
>From 8112a731f8f9b335db680e7c1a901cae4b265d4c Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 04:53:04 +0000
Subject: [PATCH 08/49] small changes
---
llvm/include/llvm/IR/OptBisect.h | 2 +-
llvm/include/llvm/Support/Range.h | 2 +-
llvm/lib/IR/OptBisect.cpp | 5 ++--
llvm/lib/Support/DebugCounter.cpp | 2 +-
llvm/lib/Support/Range.cpp | 14 +++++------
.../reduce-chunk-list/reduce-chunk-list.cpp | 2 +-
llvm/unittests/Support/RangeTest.cpp | 24 +++++++++----------
7 files changed, 25 insertions(+), 26 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index f249a52494985..b1b6e85634b80 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -73,7 +73,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// Parse range specification and set the ranges for bisection.
/// Range format: "1-10,20-30,45" (runs passes 1-10, 20-30, and 45)
- /// Returns true on parsing error.
+ /// Returns false on parsing error.
bool parseRanges(StringRef RangeStr);
/// Set ranges programmatically (for testing or other uses).
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index c05cced7c7912..56a92ffb1437a 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -55,7 +55,7 @@ class RangeUtils {
using RangeList = SmallVector<Range, 8>;
/// Parse a range specification string like "1-10,20-30,45" or "1-10:20-30:45"
- /// Returns true on error, false on success
+ /// Returns false on error, true on success
/// \param RangeStr The string to parse
/// \param Ranges Output list of parsed ranges
/// \param Separator The separator character to use (',' or ':')
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index ad0dd8930ecc1..3e29d8955900d 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -42,7 +42,7 @@ static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
} else if (Limit > 0) {
// Convert limit to range 1-Limit
std::string RangeStr = "1-" + llvm::utostr(Limit);
- if (getOptBisector().parseRanges(RangeStr)) {
+ if (!getOptBisector().parseRanges(RangeStr)) {
errs() << "Error: Invalid limit for -opt-bisect-limit: "
<< Limit << "\n";
exit(1);
@@ -54,7 +54,7 @@ static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
static cl::opt<std::string> OptBisectRanges(
"opt-bisect", cl::Hidden, cl::Optional,
cl::cb<void, const std::string &>([](const std::string &RangeStr) {
- if (getOptBisector().parseRanges(RangeStr)) {
+ if (!getOptBisector().parseRanges(RangeStr)) {
errs() << "Error: Invalid range specification for -opt-bisect: "
<< RangeStr << "\n";
exit(1);
@@ -88,7 +88,6 @@ static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
}
bool OptBisect::parseRanges(StringRef RangeStr) {
- LastBisectNum = 0;
return RangeUtils::parseRanges(RangeStr, BisectRanges);
}
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index db5682be16341..334ae3e3a58b5 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -127,7 +127,7 @@ void DebugCounter::push_back(const std::string &Val) {
RangeUtils::RangeList TempRanges;
SmallVector<Range> Chunks;
- if (RangeUtils::parseRanges(CounterPair.second, TempRanges, ':')) {
+ if (!RangeUtils::parseRanges(CounterPair.second, TempRanges, ':')) {
return;
}
Chunks.assign(TempRanges.begin(), TempRanges.end());
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index 4b1952ab8e202..0948d00f11ed4 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -17,7 +17,7 @@ bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
Ranges.clear();
if (Str.empty())
- return false;
+ return true;
// Split by the specified separator
SmallVector<StringRef, 8> Parts;
@@ -34,24 +34,24 @@ bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
SmallVector<StringRef, 4> Matches;
if (!RangeRegex.match(Part, &Matches)) {
errs() << "Invalid range format: '" << Part << "'\n";
- return true;
+ return false;
}
int64_t Begin, End;
if (Matches[1].getAsInteger(10, Begin)) {
errs() << "Failed to parse number: '" << Matches[1] << "'\n";
- return true;
+ return false;
}
if (!Matches[3].empty()) {
// Range format "begin-end"
if (Matches[3].getAsInteger(10, End)) {
errs() << "Failed to parse number: '" << Matches[3] << "'\n";
- return true;
+ return false;
}
if (Begin >= End) {
errs() << "Invalid range: " << Begin << " >= " << End << "\n";
- return true;
+ return false;
}
} else {
// Single number
@@ -62,13 +62,13 @@ bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
if (!Ranges.empty() && Begin <= Ranges.back().End) {
errs() << "Expected ranges to be in increasing order: " << Begin
<< " <= " << Ranges.back().End << "\n";
- return true;
+ return false;
}
Ranges.push_back(Range(Begin, End));
}
- return false;
+ return true;
}
bool RangeUtils::contains(const RangeList &Ranges, int64_t Value) {
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index 687367b351a6c..29cc32e05f7ee 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -85,7 +85,7 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
RangeUtils::RangeList CurrChunks;
- if (RangeUtils::parseRanges(StartChunks, CurrChunks, ','))
+ if (!RangeUtils::parseRanges(StartChunks, CurrChunks, ','))
return 1;
auto Program = sys::findProgramByName(ReproductionCmd);
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index d4a91327bd992..5719e107b8ce8 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -47,7 +47,7 @@ TEST(RangeTest, RangeOverlaps) {
TEST(RangeUtilsTest, ParseSingleNumber) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("42", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("42", Ranges));
EXPECT_EQ(Ranges.size(), 1U);
EXPECT_EQ(Ranges[0].Begin, 42);
EXPECT_EQ(Ranges[0].End, 42);
@@ -55,7 +55,7 @@ TEST(RangeUtilsTest, ParseSingleNumber) {
TEST(RangeUtilsTest, ParseSingleRange) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("10-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("10-20", Ranges));
EXPECT_EQ(Ranges.size(), 1U);
EXPECT_EQ(Ranges[0].Begin, 10);
EXPECT_EQ(Ranges[0].End, 20);
@@ -63,7 +63,7 @@ TEST(RangeUtilsTest, ParseSingleRange) {
TEST(RangeUtilsTest, ParseMultipleRanges) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
EXPECT_EQ(Ranges.size(), 3U);
// Ranges are in input order (DebugCounter style)
@@ -77,7 +77,7 @@ TEST(RangeUtilsTest, ParseMultipleRanges) {
TEST(RangeUtilsTest, ParseColonSeparated) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("1-5:10:15-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", Ranges));
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
@@ -89,7 +89,7 @@ TEST(RangeUtilsTest, ParseColonSeparated) {
TEST(RangeUtilsTest, ParseEmptyString) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("", Ranges));
EXPECT_TRUE(Ranges.empty());
}
@@ -97,19 +97,19 @@ TEST(RangeUtilsTest, ParseInvalidRanges) {
RangeUtils::RangeList Ranges;
// Invalid number
- EXPECT_TRUE(RangeUtils::parseRanges("abc", Ranges));
+ EXPECT_FALSE(RangeUtils::parseRanges("abc", Ranges));
// Invalid range (begin > end)
- EXPECT_TRUE(RangeUtils::parseRanges("10-5", Ranges));
+ EXPECT_FALSE(RangeUtils::parseRanges("10-5", Ranges));
// Out of order ranges (DebugCounter constraint)
- EXPECT_TRUE(RangeUtils::parseRanges("10,5", Ranges));
+ EXPECT_FALSE(RangeUtils::parseRanges("10,5", Ranges));
EXPECT_TRUE(RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping
}
TEST(RangeUtilsTest, Contains) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
EXPECT_TRUE(RangeUtils::contains(Ranges, 1));
EXPECT_TRUE(RangeUtils::contains(Ranges, 3));
@@ -128,7 +128,7 @@ TEST(RangeUtilsTest, Contains) {
TEST(RangeUtilsTest, RangesToString) {
RangeUtils::RangeList Ranges;
- EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
std::string Result = RangeUtils::rangesToString(Ranges);
EXPECT_EQ(Result, "1-5,10,15-20");
@@ -138,7 +138,7 @@ TEST(RangeUtilsTest, SeparatorParameter) {
RangeUtils::RangeList ColonRanges, CommaRanges;
// Test explicit separator parameters
- EXPECT_FALSE(RangeUtils::parseRanges("1-5:10:15-20", ColonRanges, ':'));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", ColonRanges, ':'));
EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", CommaRanges, ','));
EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
@@ -163,7 +163,7 @@ TEST(RangeUtilsTest, DefaultCommaSeparator) {
RangeUtils::RangeList Ranges;
// Test that comma is the default separator
- EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
>From 39c2e9aafc528eaa508fff403b1d55cdf32a80a1 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 18:19:58 +0000
Subject: [PATCH 09/49] remove opt-disable-indices
---
llvm/test/Other/opt-disable-indices.ll | 15 ---------------
1 file changed, 15 deletions(-)
delete mode 100644 llvm/test/Other/opt-disable-indices.ll
diff --git a/llvm/test/Other/opt-disable-indices.ll b/llvm/test/Other/opt-disable-indices.ll
deleted file mode 100644
index 52c2b5b1c4ffa..0000000000000
--- a/llvm/test/Other/opt-disable-indices.ll
+++ /dev/null
@@ -1,15 +0,0 @@
-; Test that verifies functionality for -opt-disable-indices
-
-; RUN: opt -O1 -opt-disable-indices=3,7 %s 2>&1 | FileCheck %s --check-prefix=CHECK-DISABLE-PASS
-; CHECK-DISABLE-PASS: BISECT: running pass (1) annotation2metadata on [module]
-; CHECK-DISABLE-PASS: BISECT: running pass (2) forceattrs on [module]
-; CHECK-DISABLE-PASS: BISECT: NOT running pass (3) inferattrs on [module]
-; CHECK-DISABLE-PASS: BISECT: running pass (4) lower-expect on foo
-; CHECK-DISABLE-PASS: BISECT: running pass (5) simplifycfg on foo
-; CHECK-DISABLE-PASS: BISECT: running pass (6) sroa on foo
-; CHECK-DISABLE-PASS: BISECT: NOT running pass (7) early-cse on foo
-; CHECK-DISABLE-PASS: BISECT: running pass (8) openmp-opt on [module]
-
-define void @foo() {
- ret void
-}
>From 21855468cfc1a908cc695f23524f89953a072a70 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 21:07:57 +0000
Subject: [PATCH 10/49] remove
---
llvm/include/llvm/IR/OptBisect.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index b1b6e85634b80..72a7c76192529 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -76,12 +76,6 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// Returns false on parsing error.
bool parseRanges(StringRef RangeStr);
- /// Set ranges programmatically (for testing or other uses).
- void setRanges(ArrayRef<Range> Ranges) {
- BisectRanges.assign(Ranges.begin(), Ranges.end());
- LastBisectNum = 0;
- }
-
/// Clear all ranges, effectively disabling bisection.
void clearRanges() {
BisectRanges.clear();
>From 950dec97ffc10d333eb53e3af191705949a73572 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 21:46:06 +0000
Subject: [PATCH 11/49] cleanup
---
llvm/include/llvm/Support/DebugCounter.h | 25 ++----------------------
llvm/include/llvm/Support/Range.h | 21 ++++++++++----------
llvm/lib/Support/DebugCounter.cpp | 10 ++--------
llvm/lib/Support/Range.cpp | 12 ++++++------
llvm/unittests/Support/RangeTest.cpp | 6 +++---
5 files changed, 24 insertions(+), 50 deletions(-)
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index 72338f7633938..cf708b0cbc4dc 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -57,9 +57,6 @@ class raw_ostream;
class DebugCounter {
public:
- // For backward compatibility, alias Range as Chunk
- using Chunk = Range;
-
/// Struct to store counter info.
class CounterInfo {
friend class DebugCounter;
@@ -75,7 +72,7 @@ class DebugCounter {
uint64_t CurrChunkIdx = 0;
StringRef Name;
StringRef Desc;
- SmallVector<Chunk> Chunks;
+ RangeUtils::RangeList Chunks;
public:
CounterInfo(StringRef Name, StringRef Desc) : Name(Name), Desc(Desc) {
@@ -87,7 +84,7 @@ class DebugCounter {
/// Return true on parsing error and print the error message on the
/// llvm::errs()
- LLVM_ABI static bool parseChunks(StringRef Str, SmallVector<Chunk> &Res);
+ LLVM_ABI static bool parseChunks(StringRef Str, RangeUtils::RangeList &Res);
/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
@@ -167,26 +164,8 @@ class DebugCounter {
}
protected:
-<<<<<<< HEAD
void addCounter(CounterInfo *Info) { Counters[Info->Name] = Info; }
bool handleCounterIncrement(CounterInfo &Info);
-=======
- unsigned addCounter(const std::string &Name, const std::string &Desc) {
- unsigned Result = RegisteredCounters.insert(Name);
- auto &C = Counters[Result];
- C = {};
- C.Desc = Desc;
- return Result;
- }
- // Struct to store counter info.
- struct CounterInfo {
- int64_t Count = 0;
- uint64_t CurrChunkIdx = 0;
- bool IsSet = false;
- std::string Desc;
- SmallVector<Range> Chunks;
- };
->>>>>>> 0242e6f869bd (range support)
MapVector<StringRef, CounterInfo *> Counters;
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 56a92ffb1437a..2041402c92925 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -30,11 +30,11 @@ struct Range {
int64_t Begin;
int64_t End;
- Range(int64_t Begin, int64_t End) : Begin(Begin), End(End) {}
- Range(int64_t Single) : Begin(Single), End(Single) {}
+ Range(const int64_t Begin, const int64_t End) : Begin(Begin), End(End) {}
+ Range(const int64_t Single) : Begin(Single), End(Single) {}
/// Check if the given value is within this range (inclusive)
- bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
+ bool contains(const int64_t Value) const { return Value >= Begin && Value <= End; }
/// Check if this range overlaps with another range
bool overlaps(const Range &Other) const {
@@ -54,25 +54,26 @@ class RangeUtils {
public:
using RangeList = SmallVector<Range, 8>;
- /// Parse a range specification string like "1-10,20-30,45" or "1-10:20-30:45"
+ /// Parse a range specification string like "1-10,20-30,45" or "1-10:20-30:45".
+ /// Ranges must be in increasing order and non-overlapping.
/// Returns false on error, true on success
/// \param RangeStr The string to parse
/// \param Ranges Output list of parsed ranges
/// \param Separator The separator character to use (',' or ':')
- static bool parseRanges(StringRef RangeStr, RangeList &Ranges, char Separator = ',');
+ static bool parseRanges(const StringRef RangeStr, RangeList &Ranges, const char Separator = ',');
/// Check if a value is contained in any of the ranges
- static bool contains(const RangeList &Ranges, int64_t Value);
+ static bool contains(const ArrayRef<Range> Ranges, const int64_t Value);
/// Convert ranges back to string representation for debugging
- static std::string rangesToString(const RangeList &Ranges, char Separator = ',');
+ static std::string rangesToString(const ArrayRef<Range> Ranges, const char Separator = ',');
- /// Print ranges to output stream (DebugCounter-compatible)
- static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges);
+ /// Print ranges to output stream
+ static void printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges);
/// Merge adjacent/consecutive ranges into single ranges
/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10]
- static RangeList mergeAdjacentRanges(ArrayRef<Range> Ranges);
+ static RangeList mergeAdjacentRanges(const ArrayRef<Range> Ranges);
};
} // end namespace llvm
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 334ae3e3a58b5..5484092141485 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -124,13 +124,6 @@ void DebugCounter::push_back(const std::string &Val) {
return;
}
StringRef CounterName = CounterPair.first;
- RangeUtils::RangeList TempRanges;
- SmallVector<Range> Chunks;
-
- if (!RangeUtils::parseRanges(CounterPair.second, TempRanges, ':')) {
- return;
- }
- Chunks.assign(TempRanges.begin(), TempRanges.end());
CounterInfo *Counter = getCounterInfo(CounterName);
if (!Counter) {
@@ -139,8 +132,9 @@ void DebugCounter::push_back(const std::string &Val) {
return;
}
+ if (!RangeUtils::parseRanges(CounterPair.second, Counter->Chunks, ':'))
+ return;
Counter->Active = Counter->IsSet = true;
- Counter->Chunks = std::move(Chunks);
}
void DebugCounter::print(raw_ostream &OS) const {
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index 0948d00f11ed4..d3b7b376adf7e 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -13,7 +13,7 @@
using namespace llvm;
-bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
+bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges, const char Separator) {
Ranges.clear();
if (Str.empty())
@@ -24,7 +24,7 @@ bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
Str.split(Parts, Separator, -1, false);
// Regex to match either single number or range "num1-num2"
- Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
+ const Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
for (StringRef Part : Parts) {
Part = Part.trim();
@@ -71,7 +71,7 @@ bool RangeUtils::parseRanges(StringRef Str, RangeList &Ranges, char Separator) {
return true;
}
-bool RangeUtils::contains(const RangeList &Ranges, int64_t Value) {
+bool RangeUtils::contains(const ArrayRef<Range> Ranges, const int64_t Value) {
for (const Range &R : Ranges) {
if (R.contains(Value))
return true;
@@ -81,7 +81,7 @@ bool RangeUtils::contains(const RangeList &Ranges, int64_t Value) {
-std::string RangeUtils::rangesToString(const RangeList &Ranges, char Separator) {
+std::string RangeUtils::rangesToString(const ArrayRef<Range> Ranges, const char Separator) {
std::ostringstream OS;
for (size_t I = 0; I < Ranges.size(); ++I) {
if (I > 0)
@@ -96,7 +96,7 @@ std::string RangeUtils::rangesToString(const RangeList &Ranges, char Separator)
return OS.str();
}
-void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges) {
+void RangeUtils::printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges) {
if (Ranges.empty()) {
OS << "empty";
} else {
@@ -115,7 +115,7 @@ void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges) {
}
}
-RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
+RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(const ArrayRef<Range> Ranges) {
if (Ranges.empty())
return {};
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 5719e107b8ce8..cddbf82c81c63 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -77,7 +77,7 @@ TEST(RangeUtilsTest, ParseMultipleRanges) {
TEST(RangeUtilsTest, ParseColonSeparated) {
RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", Ranges));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", Ranges, ':'));
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
@@ -104,7 +104,7 @@ TEST(RangeUtilsTest, ParseInvalidRanges) {
// Out of order ranges (DebugCounter constraint)
EXPECT_FALSE(RangeUtils::parseRanges("10,5", Ranges));
- EXPECT_TRUE(RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping
+ EXPECT_FALSE(RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping not allowed
}
TEST(RangeUtilsTest, Contains) {
@@ -139,7 +139,7 @@ TEST(RangeUtilsTest, SeparatorParameter) {
// Test explicit separator parameters
EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", ColonRanges, ':'));
- EXPECT_FALSE(RangeUtils::parseRanges("1-5,10,15-20", CommaRanges, ','));
+ EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", CommaRanges, ','));
EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
for (size_t I = 0; I < ColonRanges.size(); ++I) {
>From b67e43030cdd81b5fc13db63a51c9d8361de6b2d Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 21:46:22 +0000
Subject: [PATCH 12/49] format
---
llvm/include/llvm/IR/OptBisect.h | 2 +-
llvm/include/llvm/Support/Range.h | 18 +++---
llvm/lib/IR/OptBisect.cpp | 41 +++++++-------
llvm/lib/Support/Range.cpp | 41 +++++++-------
.../reduce-chunk-list/reduce-chunk-list.cpp | 3 +-
llvm/unittests/Support/RangeTest.cpp | 55 ++++++++++---------
6 files changed, 84 insertions(+), 76 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 72a7c76192529..903b7281a39e8 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -77,7 +77,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
bool parseRanges(StringRef RangeStr);
/// Clear all ranges, effectively disabling bisection.
- void clearRanges() {
+ void clearRanges() {
BisectRanges.clear();
LastBisectNum = 0;
}
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 2041402c92925..14f90c741edb0 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides utilities for parsing range specifications like "1-10,20-30,45"
-// which are commonly used in debugging and bisection tools.
+// This file provides utilities for parsing range specifications like
+// "1-10,20-30,45" which are commonly used in debugging and bisection tools.
//
//===----------------------------------------------------------------------===//
@@ -34,7 +34,9 @@ struct Range {
Range(const int64_t Single) : Begin(Single), End(Single) {}
/// Check if the given value is within this range (inclusive)
- bool contains(const int64_t Value) const { return Value >= Begin && Value <= End; }
+ bool contains(const int64_t Value) const {
+ return Value >= Begin && Value <= End;
+ }
/// Check if this range overlaps with another range
bool overlaps(const Range &Other) const {
@@ -54,19 +56,21 @@ class RangeUtils {
public:
using RangeList = SmallVector<Range, 8>;
- /// Parse a range specification string like "1-10,20-30,45" or "1-10:20-30:45".
- /// Ranges must be in increasing order and non-overlapping.
+ /// Parse a range specification string like "1-10,20-30,45" or
+ /// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping.
/// Returns false on error, true on success
/// \param RangeStr The string to parse
/// \param Ranges Output list of parsed ranges
/// \param Separator The separator character to use (',' or ':')
- static bool parseRanges(const StringRef RangeStr, RangeList &Ranges, const char Separator = ',');
+ static bool parseRanges(const StringRef RangeStr, RangeList &Ranges,
+ const char Separator = ',');
/// Check if a value is contained in any of the ranges
static bool contains(const ArrayRef<Range> Ranges, const int64_t Value);
/// Convert ranges back to string representation for debugging
- static std::string rangesToString(const ArrayRef<Range> Ranges, const char Separator = ',');
+ static std::string rangesToString(const ArrayRef<Range> Ranges,
+ const char Separator = ',');
/// Print ranges to output stream
static void printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges);
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 3e29d8955900d..7519e47b3f8b2 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -33,29 +33,30 @@ static OptDisable &getOptDisabler() {
return OptDisabler;
}
-static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
- cl::init(-1), cl::Optional,
- cl::cb<void, int>([](int Limit) {
- if (Limit == -1) {
- // -1 means run all passes, which is equivalent to no ranges
- getOptBisector().clearRanges();
- } else if (Limit > 0) {
- // Convert limit to range 1-Limit
- std::string RangeStr = "1-" + llvm::utostr(Limit);
- if (!getOptBisector().parseRanges(RangeStr)) {
- errs() << "Error: Invalid limit for -opt-bisect-limit: "
- << Limit << "\n";
- exit(1);
- }
- }
- }),
- cl::desc("Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
+static cl::opt<int> OptBisectLimit(
+ "opt-bisect-limit", cl::Hidden, cl::init(-1), cl::Optional,
+ cl::cb<void, int>([](int Limit) {
+ if (Limit == -1) {
+ // -1 means run all passes, which is equivalent to no ranges
+ getOptBisector().clearRanges();
+ } else if (Limit > 0) {
+ // Convert limit to range 1-Limit
+ std::string RangeStr = "1-" + llvm::utostr(Limit);
+ if (!getOptBisector().parseRanges(RangeStr)) {
+ errs() << "Error: Invalid limit for -opt-bisect-limit: " << Limit
+ << "\n";
+ exit(1);
+ }
+ }
+ }),
+ cl::desc(
+ "Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
static cl::opt<std::string> OptBisectRanges(
"opt-bisect", cl::Hidden, cl::Optional,
cl::cb<void, const std::string &>([](const std::string &RangeStr) {
if (!getOptBisector().parseRanges(RangeStr)) {
- errs() << "Error: Invalid range specification for -opt-bisect: "
+ errs() << "Error: Invalid range specification for -opt-bisect: "
<< RangeStr << "\n";
exit(1);
}
@@ -96,10 +97,10 @@ bool OptBisect::shouldRunPass(StringRef PassName,
assert(isEnabled());
int CurBisectNum = ++LastBisectNum;
-
+
// Check if current pass number falls within any of the specified ranges
bool ShouldRun = RangeUtils::contains(BisectRanges, CurBisectNum);
-
+
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
return ShouldRun;
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index d3b7b376adf7e..ddffbe5d9b6af 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -13,36 +13,37 @@
using namespace llvm;
-bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges, const char Separator) {
+bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges,
+ const char Separator) {
Ranges.clear();
-
+
if (Str.empty())
return true;
-
+
// Split by the specified separator
SmallVector<StringRef, 8> Parts;
Str.split(Parts, Separator, -1, false);
-
+
// Regex to match either single number or range "num1-num2"
const Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
-
+
for (StringRef Part : Parts) {
Part = Part.trim();
if (Part.empty())
continue;
-
+
SmallVector<StringRef, 4> Matches;
if (!RangeRegex.match(Part, &Matches)) {
errs() << "Invalid range format: '" << Part << "'\n";
return false;
}
-
+
int64_t Begin, End;
if (Matches[1].getAsInteger(10, Begin)) {
errs() << "Failed to parse number: '" << Matches[1] << "'\n";
return false;
}
-
+
if (!Matches[3].empty()) {
// Range format "begin-end"
if (Matches[3].getAsInteger(10, End)) {
@@ -57,17 +58,17 @@ bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges, const char
// Single number
End = Begin;
}
-
+
// Check ordering constraint (ranges must be in increasing order)
if (!Ranges.empty() && Begin <= Ranges.back().End) {
errs() << "Expected ranges to be in increasing order: " << Begin
<< " <= " << Ranges.back().End << "\n";
return false;
}
-
+
Ranges.push_back(Range(Begin, End));
}
-
+
return true;
}
@@ -79,9 +80,8 @@ bool RangeUtils::contains(const ArrayRef<Range> Ranges, const int64_t Value) {
return false;
}
-
-
-std::string RangeUtils::rangesToString(const ArrayRef<Range> Ranges, const char Separator) {
+std::string RangeUtils::rangesToString(const ArrayRef<Range> Ranges,
+ const char Separator) {
std::ostringstream OS;
for (size_t I = 0; I < Ranges.size(); ++I) {
if (I > 0)
@@ -106,7 +106,7 @@ void RangeUtils::printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges) {
OS << ':';
else
IsFirst = false;
-
+
if (R.Begin == R.End)
OS << R.Begin;
else
@@ -115,17 +115,18 @@ void RangeUtils::printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges) {
}
}
-RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(const ArrayRef<Range> Ranges) {
+RangeUtils::RangeList
+RangeUtils::mergeAdjacentRanges(const ArrayRef<Range> Ranges) {
if (Ranges.empty())
return {};
-
+
RangeList Result;
Result.push_back(Ranges[0]);
-
+
for (size_t I = 1; I < Ranges.size(); ++I) {
const Range &Current = Ranges[I];
Range &Last = Result.back();
-
+
// Check if current range is adjacent to the last merged range
if (Current.Begin == Last.End + 1) {
// Merge by extending the end of the last range
@@ -135,6 +136,6 @@ RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(const ArrayRef<Range> Rang
Result.push_back(Current);
}
}
-
+
return Result;
}
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index 29cc32e05f7ee..c09e92db60bed 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -127,6 +127,7 @@ int main(int argc, char **argv) {
}
errs() << "Minimal Chunks = ";
- RangeUtils::printRanges(llvm::errs(), RangeUtils::mergeAdjacentRanges(CurrChunks));
+ RangeUtils::printRanges(llvm::errs(),
+ RangeUtils::mergeAdjacentRanges(CurrChunks));
errs() << "\n";
}
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index cddbf82c81c63..94fc281386cdd 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -36,7 +36,7 @@ TEST(RangeTest, RangeOverlaps) {
Range R2(3, 8);
Range R3(6, 10);
Range R4(11, 15);
-
+
EXPECT_TRUE(R1.overlaps(R2));
EXPECT_TRUE(R2.overlaps(R1));
EXPECT_TRUE(R2.overlaps(R3));
@@ -65,7 +65,7 @@ TEST(RangeUtilsTest, ParseMultipleRanges) {
RangeUtils::RangeList Ranges;
EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
EXPECT_EQ(Ranges.size(), 3U);
-
+
// Ranges are in input order (DebugCounter style)
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
@@ -95,22 +95,23 @@ TEST(RangeUtilsTest, ParseEmptyString) {
TEST(RangeUtilsTest, ParseInvalidRanges) {
RangeUtils::RangeList Ranges;
-
+
// Invalid number
EXPECT_FALSE(RangeUtils::parseRanges("abc", Ranges));
-
+
// Invalid range (begin > end)
EXPECT_FALSE(RangeUtils::parseRanges("10-5", Ranges));
-
+
// Out of order ranges (DebugCounter constraint)
EXPECT_FALSE(RangeUtils::parseRanges("10,5", Ranges));
- EXPECT_FALSE(RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping not allowed
+ EXPECT_FALSE(
+ RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping not allowed
}
TEST(RangeUtilsTest, Contains) {
RangeUtils::RangeList Ranges;
EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
-
+
EXPECT_TRUE(RangeUtils::contains(Ranges, 1));
EXPECT_TRUE(RangeUtils::contains(Ranges, 3));
EXPECT_TRUE(RangeUtils::contains(Ranges, 5));
@@ -118,7 +119,7 @@ TEST(RangeUtilsTest, Contains) {
EXPECT_TRUE(RangeUtils::contains(Ranges, 15));
EXPECT_TRUE(RangeUtils::contains(Ranges, 18));
EXPECT_TRUE(RangeUtils::contains(Ranges, 20));
-
+
EXPECT_FALSE(RangeUtils::contains(Ranges, 6));
EXPECT_FALSE(RangeUtils::contains(Ranges, 9));
EXPECT_FALSE(RangeUtils::contains(Ranges, 11));
@@ -129,24 +130,24 @@ TEST(RangeUtilsTest, Contains) {
TEST(RangeUtilsTest, RangesToString) {
RangeUtils::RangeList Ranges;
EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
-
+
std::string Result = RangeUtils::rangesToString(Ranges);
EXPECT_EQ(Result, "1-5,10,15-20");
}
TEST(RangeUtilsTest, SeparatorParameter) {
RangeUtils::RangeList ColonRanges, CommaRanges;
-
+
// Test explicit separator parameters
EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", ColonRanges, ':'));
EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", CommaRanges, ','));
-
+
EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
for (size_t I = 0; I < ColonRanges.size(); ++I) {
EXPECT_EQ(ColonRanges[I].Begin, CommaRanges[I].Begin);
EXPECT_EQ(ColonRanges[I].End, CommaRanges[I].End);
}
-
+
// Test that both work with contains()
EXPECT_TRUE(RangeUtils::contains(ColonRanges, 3));
EXPECT_TRUE(RangeUtils::contains(CommaRanges, 3));
@@ -154,14 +155,14 @@ TEST(RangeUtilsTest, SeparatorParameter) {
EXPECT_TRUE(RangeUtils::contains(CommaRanges, 10));
EXPECT_TRUE(RangeUtils::contains(ColonRanges, 18));
EXPECT_TRUE(RangeUtils::contains(CommaRanges, 18));
-
+
EXPECT_FALSE(RangeUtils::contains(ColonRanges, 8));
EXPECT_FALSE(RangeUtils::contains(CommaRanges, 8));
}
TEST(RangeUtilsTest, DefaultCommaSeparator) {
RangeUtils::RangeList Ranges;
-
+
// Test that comma is the default separator
EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
EXPECT_EQ(Ranges.size(), 3U);
@@ -175,17 +176,17 @@ TEST(RangeUtilsTest, DefaultCommaSeparator) {
TEST(RangeTest, MergeAdjacentRanges) {
RangeUtils::RangeList Input, Expected, Result;
-
+
// Empty input
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_TRUE(Result.empty());
-
+
// Single range - no change
Input.push_back(Range(5, 10));
Expected.push_back(Range(5, 10));
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
-
+
// Adjacent ranges should merge
Input.clear();
Expected.clear();
@@ -195,32 +196,32 @@ TEST(RangeTest, MergeAdjacentRanges) {
Expected.push_back(Range(1, 9));
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
-
+
// Non-adjacent ranges should not merge
Input.clear();
Expected.clear();
Input.push_back(Range(1, 3));
- Input.push_back(Range(5, 7)); // Gap between 3 and 5
+ Input.push_back(Range(5, 7)); // Gap between 3 and 5
Input.push_back(Range(10, 12)); // Gap between 7 and 10
Expected.push_back(Range(1, 3));
Expected.push_back(Range(5, 7));
Expected.push_back(Range(10, 12));
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
-
+
// Mixed adjacent and non-adjacent
Input.clear();
Expected.clear();
Input.push_back(Range(1, 3));
- Input.push_back(Range(4, 6)); // Adjacent to first
- Input.push_back(Range(8, 10)); // Gap
- Input.push_back(Range(11, 13)); // Adjacent to third
- Input.push_back(Range(14, 16)); // Adjacent to fourth
- Expected.push_back(Range(1, 6)); // Merged 1-3 and 4-6
- Expected.push_back(Range(8, 16)); // Merged 8-10, 11-13, 14-16
+ Input.push_back(Range(4, 6)); // Adjacent to first
+ Input.push_back(Range(8, 10)); // Gap
+ Input.push_back(Range(11, 13)); // Adjacent to third
+ Input.push_back(Range(14, 16)); // Adjacent to fourth
+ Expected.push_back(Range(1, 6)); // Merged 1-3 and 4-6
+ Expected.push_back(Range(8, 16)); // Merged 8-10, 11-13, 14-16
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
-
+
// Single numbers that are adjacent
Input.clear();
Expected.clear();
>From ff7f1d1bc86ef299f89ef62b6df69e3099543e08 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 22:32:30 +0000
Subject: [PATCH 13/49] use Expect for Range
---
llvm/include/llvm/IR/OptBisect.h | 8 +-
llvm/include/llvm/Support/Range.h | 10 +-
llvm/lib/IR/OptBisect.cpp | 23 +++--
llvm/lib/Support/DebugCounter.cpp | 8 +-
llvm/lib/Support/Range.cpp | 45 ++++++---
llvm/test/Other/debugcounter-multi-ranges.ll | 92 +++++++++++++++----
.../reduce-chunk-list/reduce-chunk-list.cpp | 9 +-
7 files changed, 142 insertions(+), 53 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 903b7281a39e8..0c5c57b1771e0 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -71,10 +71,10 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// isEnabled() should return true before calling shouldRunPass().
bool isEnabled() const override { return !BisectRanges.empty(); }
- /// Parse range specification and set the ranges for bisection.
- /// Range format: "1-10,20-30,45" (runs passes 1-10, 20-30, and 45)
- /// Returns false on parsing error.
- bool parseRanges(StringRef RangeStr);
+ /// Set ranges directly from a RangeList
+ void setRanges(RangeUtils::RangeList Ranges) {
+ BisectRanges = std::move(Ranges);
+ }
/// Clear all ranges, effectively disabling bisection.
void clearRanges() {
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 14f90c741edb0..9e3e68e7f4596 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include <cstdint>
namespace llvm {
@@ -58,10 +59,15 @@ class RangeUtils {
/// Parse a range specification string like "1-10,20-30,45" or
/// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping.
- /// Returns false on error, true on success
/// \param RangeStr The string to parse
- /// \param Ranges Output list of parsed ranges
/// \param Separator The separator character to use (',' or ':')
+ /// \returns Expected<RangeList> containing the parsed ranges on success,
+ /// or an Error on failure
+ static Expected<RangeList> parseRanges(const StringRef RangeStr,
+ const char Separator = ',');
+
+ /// Legacy interface for backward compatibility.
+ /// \deprecated Use the Expected<RangeList> version instead
static bool parseRanges(const StringRef RangeStr, RangeList &Ranges,
const char Separator = ',');
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 7519e47b3f8b2..b2bce5a9cf524 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -42,11 +42,15 @@ static cl::opt<int> OptBisectLimit(
} else if (Limit > 0) {
// Convert limit to range 1-Limit
std::string RangeStr = "1-" + llvm::utostr(Limit);
- if (!getOptBisector().parseRanges(RangeStr)) {
- errs() << "Error: Invalid limit for -opt-bisect-limit: " << Limit
- << "\n";
+ auto Ranges = RangeUtils::parseRanges(RangeStr);
+ if (!Ranges) {
+ handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
+ errs() << "Error: Invalid limit for -opt-bisect-limit: " << Limit
+ << " (" << E.getMessage() << ")\n";
+ });
exit(1);
}
+ getOptBisector().setRanges(std::move(*Ranges));
}
}),
cl::desc(
@@ -55,11 +59,15 @@ static cl::opt<int> OptBisectLimit(
static cl::opt<std::string> OptBisectRanges(
"opt-bisect", cl::Hidden, cl::Optional,
cl::cb<void, const std::string &>([](const std::string &RangeStr) {
- if (!getOptBisector().parseRanges(RangeStr)) {
- errs() << "Error: Invalid range specification for -opt-bisect: "
- << RangeStr << "\n";
+ auto Ranges = RangeUtils::parseRanges(RangeStr);
+ if (!Ranges) {
+ handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
+ errs() << "Error: Invalid range specification for -opt-bisect: "
+ << RangeStr << " (" << E.getMessage() << ")\n";
+ });
exit(1);
}
+ getOptBisector().setRanges(std::move(*Ranges));
}),
cl::desc("Run optimization passes only for the specified ranges. "
"Format: '1-10,20-30,45' (runs passes 1-10, 20-30, and 45)"));
@@ -88,9 +96,6 @@ static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
<< " on " << TargetDesc << '\n';
}
-bool OptBisect::parseRanges(StringRef RangeStr) {
- return RangeUtils::parseRanges(RangeStr, BisectRanges);
-}
bool OptBisect::shouldRunPass(StringRef PassName,
StringRef IRDescription) const {
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 5484092141485..f94ed4b804929 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -132,8 +132,14 @@ void DebugCounter::push_back(const std::string &Val) {
return;
}
- if (!RangeUtils::parseRanges(CounterPair.second, Counter->Chunks, ':'))
+ auto ExpectedChunks = RangeUtils::parseRanges(CounterPair.second, ':');
+ if (!ExpectedChunks) {
+ handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
+ errs() << "DebugCounter Error: " << E.getMessage() << "\n";
+ });
return;
+ }
+ Counter->Chunks = std::move(*ExpectedChunks);
Counter->Active = Counter->IsSet = true;
}
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index ddffbe5d9b6af..aa69fe35213bc 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -7,18 +7,19 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Range.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
#include <sstream>
using namespace llvm;
-bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges,
- const char Separator) {
- Ranges.clear();
+Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
+ const char Separator) {
+ RangeList Ranges;
if (Str.empty())
- return true;
+ return std::move(Ranges);
// Split by the specified separator
SmallVector<StringRef, 8> Parts;
@@ -34,25 +35,25 @@ bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges,
SmallVector<StringRef, 4> Matches;
if (!RangeRegex.match(Part, &Matches)) {
- errs() << "Invalid range format: '" << Part << "'\n";
- return false;
+ return createStringError(std::errc::invalid_argument,
+ "Invalid range format: '%s'", Part.str().c_str());
}
int64_t Begin, End;
if (Matches[1].getAsInteger(10, Begin)) {
- errs() << "Failed to parse number: '" << Matches[1] << "'\n";
- return false;
+ return createStringError(std::errc::invalid_argument,
+ "Failed to parse number: '%s'", Matches[1].str().c_str());
}
if (!Matches[3].empty()) {
// Range format "begin-end"
if (Matches[3].getAsInteger(10, End)) {
- errs() << "Failed to parse number: '" << Matches[3] << "'\n";
- return false;
+ return createStringError(std::errc::invalid_argument,
+ "Failed to parse number: '%s'", Matches[3].str().c_str());
}
if (Begin >= End) {
- errs() << "Invalid range: " << Begin << " >= " << End << "\n";
- return false;
+ return createStringError(std::errc::invalid_argument,
+ "Invalid range: %lld >= %lld", Begin, End);
}
} else {
// Single number
@@ -61,14 +62,28 @@ bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges,
// Check ordering constraint (ranges must be in increasing order)
if (!Ranges.empty() && Begin <= Ranges.back().End) {
- errs() << "Expected ranges to be in increasing order: " << Begin
- << " <= " << Ranges.back().End << "\n";
- return false;
+ return createStringError(std::errc::invalid_argument,
+ "Expected ranges to be in increasing order: %lld <= %lld",
+ Begin, Ranges.back().End);
}
Ranges.push_back(Range(Begin, End));
}
+ return std::move(Ranges);
+}
+
+bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges,
+ const char Separator) {
+ auto ExpectedRanges = parseRanges(Str, Separator);
+ if (!ExpectedRanges) {
+ // For backward compatibility, print error to stderr
+ handleAllErrors(ExpectedRanges.takeError(), [](const StringError &E) {
+ errs() << E.getMessage() << "\n";
+ });
+ return false;
+ }
+ Ranges = std::move(*ExpectedRanges);
return true;
}
diff --git a/llvm/test/Other/debugcounter-multi-ranges.ll b/llvm/test/Other/debugcounter-multi-ranges.ll
index 30cdbc6e40c0b..aa4f0aa247329 100644
--- a/llvm/test/Other/debugcounter-multi-ranges.ll
+++ b/llvm/test/Other/debugcounter-multi-ranges.ll
@@ -1,12 +1,20 @@
; REQUIRES: asserts
-; Test debug counter with multiple ranges using colon separators
-; (DebugCounter uses colon separators to avoid conflicts with cl::CommaSeparated)
+; Test debug counter with multiple ranges
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=1:3:5 < %s | FileCheck %s --check-prefix=CHECK-COLON
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2:4:6-7 < %s | FileCheck %s --check-prefix=CHECK-MIXED-COLON
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1:3:5 < %s | FileCheck %s --check-prefix=CHECK-SINGLE
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2:4:6-7 < %s | FileCheck %s --check-prefix=CHECK-MIXED
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-7 < %s | FileCheck %s --check-prefix=CHECK-ALL
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=100 < %s | FileCheck %s --check-prefix=CHECK-NONE
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=7 < %s | FileCheck %s --check-prefix=CHECK-LAST
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1 < %s | FileCheck %s --check-prefix=CHECK-FIRST
+
+; Test error cases - these should produce error messages but not crash
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=invalid 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-INVALID
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=5-2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-BACKWARDS
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:3:2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-UNORDERED
; Test that with debug counters on, we can selectively apply transformations
-; using different range syntaxes. All variants should produce the same result.
+; using different range specifications and edge cases.
; Original function has 8 dead instructions that DCE can eliminate
define void @test() {
@@ -21,18 +29,62 @@ define void @test() {
ret void
}
-; Test colon separator: apply transformations 1, 3, 5 (eliminate dead2, dead4, dead6)
-; CHECK-COLON-LABEL: @test
-; CHECK-COLON-NEXT: %dead1 = add i32 1, 2
-; CHECK-COLON-NEXT: %dead3 = add i32 5, 6
-; CHECK-COLON-NEXT: %dead5 = add i32 9, 10
-; CHECK-COLON-NEXT: %dead7 = add i32 13, 14
-; CHECK-COLON-NEXT: %dead8 = add i32 15, 16
-; CHECK-COLON-NEXT: ret void
-
-; Test mixed ranges with colon: apply transformations 1-2, 4, 6-7 (eliminate dead2, dead3, dead5, dead7, dead8)
-; CHECK-MIXED-COLON-LABEL: @test
-; CHECK-MIXED-COLON-NEXT: %dead1 = add i32 1, 2
-; CHECK-MIXED-COLON-NEXT: %dead4 = add i32 7, 8
-; CHECK-MIXED-COLON-NEXT: %dead6 = add i32 11, 12
-; CHECK-MIXED-COLON-NEXT: ret void
+; Test single values: apply transformations 1, 3, 5 (eliminate dead2, dead4, dead6)
+; CHECK-SINGLE-LABEL: @test
+; CHECK-SINGLE-NEXT: %dead1 = add i32 1, 2
+; CHECK-SINGLE-NEXT: %dead3 = add i32 5, 6
+; CHECK-SINGLE-NEXT: %dead5 = add i32 9, 10
+; CHECK-SINGLE-NEXT: %dead7 = add i32 13, 14
+; CHECK-SINGLE-NEXT: %dead8 = add i32 15, 16
+; CHECK-SINGLE-NEXT: ret void
+
+; Test mixed ranges: apply transformations 1-2, 4, 6-7 (eliminate dead2, dead3, dead5, dead7, dead8)
+; CHECK-MIXED-LABEL: @test
+; CHECK-MIXED-NEXT: %dead1 = add i32 1, 2
+; CHECK-MIXED-NEXT: %dead4 = add i32 7, 8
+; CHECK-MIXED-NEXT: %dead6 = add i32 11, 12
+; CHECK-MIXED-NEXT: ret void
+
+; Test all range: apply transformations 1-7 (eliminate all dead instructions except dead1)
+; CHECK-ALL-LABEL: @test
+; CHECK-ALL-NEXT: %dead1 = add i32 1, 2
+; CHECK-ALL-NEXT: ret void
+
+; Test out of range: apply transformation 100 (eliminate nothing, counter too high)
+; CHECK-NONE-LABEL: @test
+; CHECK-NONE-NEXT: %dead1 = add i32 1, 2
+; CHECK-NONE-NEXT: %dead2 = add i32 3, 4
+; CHECK-NONE-NEXT: %dead3 = add i32 5, 6
+; CHECK-NONE-NEXT: %dead4 = add i32 7, 8
+; CHECK-NONE-NEXT: %dead5 = add i32 9, 10
+; CHECK-NONE-NEXT: %dead6 = add i32 11, 12
+; CHECK-NONE-NEXT: %dead7 = add i32 13, 14
+; CHECK-NONE-NEXT: %dead8 = add i32 15, 16
+; CHECK-NONE-NEXT: ret void
+
+; Test last transformation: apply transformation 7 (eliminate dead8)
+; CHECK-LAST-LABEL: @test
+; CHECK-LAST-NEXT: %dead1 = add i32 1, 2
+; CHECK-LAST-NEXT: %dead2 = add i32 3, 4
+; CHECK-LAST-NEXT: %dead3 = add i32 5, 6
+; CHECK-LAST-NEXT: %dead4 = add i32 7, 8
+; CHECK-LAST-NEXT: %dead5 = add i32 9, 10
+; CHECK-LAST-NEXT: %dead6 = add i32 11, 12
+; CHECK-LAST-NEXT: %dead7 = add i32 13, 14
+; CHECK-LAST-NEXT: ret void
+
+; Test first transformation: apply transformation 1 (eliminate dead2)
+; CHECK-FIRST-LABEL: @test
+; CHECK-FIRST-NEXT: %dead1 = add i32 1, 2
+; CHECK-FIRST-NEXT: %dead3 = add i32 5, 6
+; CHECK-FIRST-NEXT: %dead4 = add i32 7, 8
+; CHECK-FIRST-NEXT: %dead5 = add i32 9, 10
+; CHECK-FIRST-NEXT: %dead6 = add i32 11, 12
+; CHECK-FIRST-NEXT: %dead7 = add i32 13, 14
+; CHECK-FIRST-NEXT: %dead8 = add i32 15, 16
+; CHECK-FIRST-NEXT: ret void
+
+; Error case checks
+; CHECK-ERROR-INVALID: Invalid range format: 'invalid'
+; CHECK-ERROR-BACKWARDS: Invalid range: 5 >= 2
+; CHECK-ERROR-UNORDERED: Expected ranges to be in increasing order: 2 <= 3
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index c09e92db60bed..cabaf0f865055 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -84,9 +84,14 @@ bool increaseGranularity(RangeUtils::RangeList &Chunks) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
- RangeUtils::RangeList CurrChunks;
- if (!RangeUtils::parseRanges(StartChunks, CurrChunks, ','))
+ auto ExpectedChunks = RangeUtils::parseRanges(StartChunks, ',');
+ if (!ExpectedChunks) {
+ handleAllErrors(ExpectedChunks.takeError(), [](const StringError &E) {
+ errs() << "Error parsing chunks: " << E.getMessage() << "\n";
+ });
return 1;
+ }
+ RangeUtils::RangeList CurrChunks = std::move(*ExpectedChunks);
auto Program = sys::findProgramByName(ReproductionCmd);
if (!Program) {
>From 193500d84cb50168dab0e803bbc6f71ba6a12557 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 22:32:37 +0000
Subject: [PATCH 14/49] format
---
llvm/include/llvm/Support/Range.h | 2 +-
llvm/lib/IR/OptBisect.cpp | 1 -
llvm/lib/Support/Range.cpp | 20 ++++++++++++--------
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 9e3e68e7f4596..b22ff312513e3 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -66,7 +66,7 @@ class RangeUtils {
static Expected<RangeList> parseRanges(const StringRef RangeStr,
const char Separator = ',');
- /// Legacy interface for backward compatibility.
+ /// Legacy interface for backward compatibility.
/// \deprecated Use the Expected<RangeList> version instead
static bool parseRanges(const StringRef RangeStr, RangeList &Ranges,
const char Separator = ',');
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index b2bce5a9cf524..6de86e7bae0b6 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -96,7 +96,6 @@ static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
<< " on " << TargetDesc << '\n';
}
-
bool OptBisect::shouldRunPass(StringRef PassName,
StringRef IRDescription) const {
assert(isEnabled());
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index aa69fe35213bc..2ea131fffb434 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -15,7 +15,7 @@
using namespace llvm;
Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
- const char Separator) {
+ const char Separator) {
RangeList Ranges;
if (Str.empty())
@@ -36,24 +36,27 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
SmallVector<StringRef, 4> Matches;
if (!RangeRegex.match(Part, &Matches)) {
return createStringError(std::errc::invalid_argument,
- "Invalid range format: '%s'", Part.str().c_str());
+ "Invalid range format: '%s'",
+ Part.str().c_str());
}
int64_t Begin, End;
if (Matches[1].getAsInteger(10, Begin)) {
return createStringError(std::errc::invalid_argument,
- "Failed to parse number: '%s'", Matches[1].str().c_str());
+ "Failed to parse number: '%s'",
+ Matches[1].str().c_str());
}
if (!Matches[3].empty()) {
// Range format "begin-end"
if (Matches[3].getAsInteger(10, End)) {
return createStringError(std::errc::invalid_argument,
- "Failed to parse number: '%s'", Matches[3].str().c_str());
+ "Failed to parse number: '%s'",
+ Matches[3].str().c_str());
}
if (Begin >= End) {
return createStringError(std::errc::invalid_argument,
- "Invalid range: %lld >= %lld", Begin, End);
+ "Invalid range: %lld >= %lld", Begin, End);
}
} else {
// Single number
@@ -62,9 +65,10 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
// Check ordering constraint (ranges must be in increasing order)
if (!Ranges.empty() && Begin <= Ranges.back().End) {
- return createStringError(std::errc::invalid_argument,
- "Expected ranges to be in increasing order: %lld <= %lld",
- Begin, Ranges.back().End);
+ return createStringError(
+ std::errc::invalid_argument,
+ "Expected ranges to be in increasing order: %lld <= %lld", Begin,
+ Ranges.back().End);
}
Ranges.push_back(Range(Begin, End));
>From e3a73d2489afd54587d4f12a0986875ce39808fe Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 22:35:47 +0000
Subject: [PATCH 15/49] fix hang
---
llvm/lib/Support/DebugCounter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index f94ed4b804929..89590f6023f83 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -137,7 +137,7 @@ void DebugCounter::push_back(const std::string &Val) {
handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
errs() << "DebugCounter Error: " << E.getMessage() << "\n";
});
- return;
+ exit(1);
}
Counter->Chunks = std::move(*ExpectedChunks);
Counter->Active = Counter->IsSet = true;
>From 5975e0cfb4fd56b2ad4048e64e0a7e8cbbdf1e29 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 3 Sep 2025 22:57:01 +0000
Subject: [PATCH 16/49] fix error handling tests
---
llvm/lib/Support/DebugCounter.cpp | 2 +-
llvm/test/Other/debugcounter-multi-ranges.ll | 38 ++++++++++++++++----
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 89590f6023f83..350629415ffd6 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -121,7 +121,7 @@ void DebugCounter::push_back(const std::string &Val) {
auto CounterPair = StringRef(Val).split('=');
if (CounterPair.second.empty()) {
errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";
- return;
+ exit(1);
}
StringRef CounterName = CounterPair.first;
diff --git a/llvm/test/Other/debugcounter-multi-ranges.ll b/llvm/test/Other/debugcounter-multi-ranges.ll
index aa4f0aa247329..7d9b1949a5499 100644
--- a/llvm/test/Other/debugcounter-multi-ranges.ll
+++ b/llvm/test/Other/debugcounter-multi-ranges.ll
@@ -1,6 +1,7 @@
; REQUIRES: asserts
-; Test debug counter with multiple ranges
+; Test debug counter with multiple ranges
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=0 < %s | FileCheck %s --check-prefix=CHECK-ZERO
; RUN: opt -passes=dce -S -debug-counter=dce-transform=1:3:5 < %s | FileCheck %s --check-prefix=CHECK-SINGLE
; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2:4:6-7 < %s | FileCheck %s --check-prefix=CHECK-MIXED
; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-7 < %s | FileCheck %s --check-prefix=CHECK-ALL
@@ -12,9 +13,16 @@
; RUN: not opt -passes=dce -S -debug-counter=dce-transform=invalid 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-INVALID
; RUN: not opt -passes=dce -S -debug-counter=dce-transform=5-2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-BACKWARDS
; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:3:2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-UNORDERED
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=abc-def 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-NON-NUMERIC
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1-abc 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-MIXED
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:2:3:2:4 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-COMPLEX-UNORDERED
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1--5 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-DOUBLE-DASH
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=-5 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-NEGATIVE
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform= 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-EMPTY
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:1:1 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-DUPLICATE
; Test that with debug counters on, we can selectively apply transformations
-; using different range specifications and edge cases.
+; using different range specifications. Also check that we catch errors during parsing.
; Original function has 8 dead instructions that DCE can eliminate
define void @test() {
@@ -29,6 +37,17 @@ define void @test() {
ret void
}
+; Test zero: eliminate transformation 0
+; CHECK-ZERO-LABEL: @test
+; CHECK-ZERO-NEXT: %dead2 = add i32 3, 4
+; CHECK-ZERO-NEXT: %dead3 = add i32 5, 6
+; CHECK-ZERO-NEXT: %dead4 = add i32 7, 8
+; CHECK-ZERO-NEXT: %dead5 = add i32 9, 10
+; CHECK-ZERO-NEXT: %dead6 = add i32 11, 12
+; CHECK-ZERO-NEXT: %dead7 = add i32 13, 14
+; CHECK-ZERO-NEXT: %dead8 = add i32 15, 16
+; CHECK-ZERO-NEXT: ret void
+
; Test single values: apply transformations 1, 3, 5 (eliminate dead2, dead4, dead6)
; CHECK-SINGLE-LABEL: @test
; CHECK-SINGLE-NEXT: %dead1 = add i32 1, 2
@@ -84,7 +103,14 @@ define void @test() {
; CHECK-FIRST-NEXT: %dead8 = add i32 15, 16
; CHECK-FIRST-NEXT: ret void
-; Error case checks
-; CHECK-ERROR-INVALID: Invalid range format: 'invalid'
-; CHECK-ERROR-BACKWARDS: Invalid range: 5 >= 2
-; CHECK-ERROR-UNORDERED: Expected ranges to be in increasing order: 2 <= 3
+; Error case checks - test comprehensive error handling
+; CHECK-ERROR-INVALID: DebugCounter Error: Invalid range format: 'invalid'
+; CHECK-ERROR-BACKWARDS: DebugCounter Error: Invalid range: 5 >= 2
+; CHECK-ERROR-UNORDERED: DebugCounter Error: Expected ranges to be in increasing order: 2 <= 3
+; CHECK-ERROR-NON-NUMERIC: DebugCounter Error: Invalid range format: 'abc-def'
+; CHECK-ERROR-MIXED: DebugCounter Error: Invalid range format: '1-abc'
+; CHECK-ERROR-COMPLEX-UNORDERED: DebugCounter Error: Expected ranges to be in increasing order: 2 <= 3
+; CHECK-ERROR-DOUBLE-DASH: DebugCounter Error: Invalid range format: '1--5'
+; CHECK-ERROR-NEGATIVE: DebugCounter Error: Invalid range format: '-5'
+; CHECK-ERROR-EMPTY: DebugCounter Error: dce-transform= does not have an = in it
+; CHECK-ERROR-DUPLICATE: DebugCounter Error: Expected ranges to be in increasing order: 1 <= 1
>From d4a86daa58752dce12553534f7556eedb785f62e Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 17:23:43 +0000
Subject: [PATCH 17/49] format
---
llvm/lib/Support/Range.cpp | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index 2ea131fffb434..f2567970c6670 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -34,42 +34,36 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
continue;
SmallVector<StringRef, 4> Matches;
- if (!RangeRegex.match(Part, &Matches)) {
+ if (!RangeRegex.match(Part, &Matches))
return createStringError(std::errc::invalid_argument,
"Invalid range format: '%s'",
Part.str().c_str());
- }
int64_t Begin, End;
- if (Matches[1].getAsInteger(10, Begin)) {
+ if (Matches[1].getAsInteger(10, Begin))
return createStringError(std::errc::invalid_argument,
"Failed to parse number: '%s'",
Matches[1].str().c_str());
- }
if (!Matches[3].empty()) {
// Range format "begin-end"
- if (Matches[3].getAsInteger(10, End)) {
+ if (Matches[3].getAsInteger(10, End))
return createStringError(std::errc::invalid_argument,
"Failed to parse number: '%s'",
Matches[3].str().c_str());
- }
- if (Begin >= End) {
+ if (Begin >= End)
return createStringError(std::errc::invalid_argument,
"Invalid range: %lld >= %lld", Begin, End);
- }
- } else {
+ } else
// Single number
End = Begin;
- }
// Check ordering constraint (ranges must be in increasing order)
- if (!Ranges.empty() && Begin <= Ranges.back().End) {
+ if (!Ranges.empty() && Begin <= Ranges.back().End)
return createStringError(
std::errc::invalid_argument,
"Expected ranges to be in increasing order: %lld <= %lld", Begin,
Ranges.back().End);
- }
Ranges.push_back(Range(Begin, End));
}
@@ -106,19 +100,18 @@ std::string RangeUtils::rangesToString(const ArrayRef<Range> Ranges,
if (I > 0)
OS << Separator;
const Range &R = Ranges[I];
- if (R.Begin == R.End) {
+ if (R.Begin == R.End)
OS << R.Begin;
- } else {
+ else
OS << R.Begin << "-" << R.End;
- }
}
return OS.str();
}
void RangeUtils::printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges) {
- if (Ranges.empty()) {
+ if (Ranges.empty())
OS << "empty";
- } else {
+ else {
bool IsFirst = true;
for (const Range &R : Ranges) {
if (!IsFirst)
>From b308cb5e4a480b7af960146c0ae5a8fe4c56496b Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 17:31:34 +0000
Subject: [PATCH 18/49] cleanup
---
llvm/include/llvm/Support/Range.h | 8 ++++++++
llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp | 3 +--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index b22ff312513e3..5fb73c5cd99a4 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -47,6 +47,14 @@ struct Range {
/// Get the size of this range
int64_t size() const { return End - Begin + 1; }
+ std::string toString() const {
+ return std::to_string(Begin) + "-" + std::to_string(End);
+ }
+
+ void print(raw_ostream &OS) const {
+ OS << Begin << "-" << End;
+ }
+
bool operator==(const Range &Other) const {
return Begin == Other.Begin && End == Other.End;
}
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index cabaf0f865055..eb588dbe85aad 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -117,8 +117,7 @@ int main(int argc, char **argv) {
Range Testing = CurrChunks[Idx];
errs() << "Trying to remove : " << Testing.Begin;
- if (Testing.Begin != Testing.End)
- errs() << "-" << Testing.End;
+ Testing.print(errs());
errs() << "\n";
CurrChunks.erase(CurrChunks.begin() + Idx);
>From 4b0dd7c0d9848104707c276372459ba1e9320b33 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 17:31:48 +0000
Subject: [PATCH 19/49] clang format
---
llvm/include/llvm/Support/Range.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 5fb73c5cd99a4..7f093d7efb631 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -51,9 +51,7 @@ struct Range {
return std::to_string(Begin) + "-" + std::to_string(End);
}
- void print(raw_ostream &OS) const {
- OS << Begin << "-" << End;
- }
+ void print(raw_ostream &OS) const { OS << Begin << "-" << End; }
bool operator==(const Range &Other) const {
return Begin == Other.Begin && End == Other.End;
>From 32b235561772a83fd0d831480f4fb399272647f8 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 17:49:40 +0000
Subject: [PATCH 20/49] fix minor formatting bug
---
llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index eb588dbe85aad..50a8cb246d290 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -116,7 +116,7 @@ int main(int argc, char **argv) {
break;
Range Testing = CurrChunks[Idx];
- errs() << "Trying to remove : " << Testing.Begin;
+ errs() << "Trying to remove : ";
Testing.print(errs());
errs() << "\n";
>From 59a57eefbe2979112a408270717e36900265fdab Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 18:56:02 +0000
Subject: [PATCH 21/49] small bug
---
llvm/lib/IR/OptBisect.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 6de86e7bae0b6..1c349c2178b2d 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -41,7 +41,7 @@ static cl::opt<int> OptBisectLimit(
getOptBisector().clearRanges();
} else if (Limit > 0) {
// Convert limit to range 1-Limit
- std::string RangeStr = "1-" + llvm::utostr(Limit);
+ std::string RangeStr = Limit == 1? "1" : "1-" + llvm::utostr(Limit);
auto Ranges = RangeUtils::parseRanges(RangeStr);
if (!Ranges) {
handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
>From 2c2c3848b09c2167cf1cf2b2ed7e880b1f146a46 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 18:56:12 +0000
Subject: [PATCH 22/49] format
---
llvm/lib/IR/OptBisect.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 1c349c2178b2d..33f345cd2c3b8 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -41,7 +41,7 @@ static cl::opt<int> OptBisectLimit(
getOptBisector().clearRanges();
} else if (Limit > 0) {
// Convert limit to range 1-Limit
- std::string RangeStr = Limit == 1? "1" : "1-" + llvm::utostr(Limit);
+ std::string RangeStr = Limit == 1 ? "1" : "1-" + llvm::utostr(Limit);
auto Ranges = RangeUtils::parseRanges(RangeStr);
if (!Ranges) {
handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
>From 2bd51b7c821b68515ad6c209fe7d498e38216d1b Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 19:56:43 +0000
Subject: [PATCH 23/49] allow -opt-bisect=0 and -opt-bisect=-1
---
llvm/lib/IR/OptBisect.cpp | 15 ++++++++++++---
llvm/test/Other/opt-bisect-ranges.ll | 18 ++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 33f345cd2c3b8..4bf920a40879c 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -37,8 +37,11 @@ static cl::opt<int> OptBisectLimit(
"opt-bisect-limit", cl::Hidden, cl::init(-1), cl::Optional,
cl::cb<void, int>([](int Limit) {
if (Limit == -1) {
- // -1 means run all passes, which is equivalent to no ranges
- getOptBisector().clearRanges();
+ // -1 means run all passes
+ getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
+ } else if (Limit == 0) {
+ // 0 means run no passes
+ getOptBisector().setRanges({{0, 0}});
} else if (Limit > 0) {
// Convert limit to range 1-Limit
std::string RangeStr = Limit == 1 ? "1" : "1-" + llvm::utostr(Limit);
@@ -59,6 +62,12 @@ static cl::opt<int> OptBisectLimit(
static cl::opt<std::string> OptBisectRanges(
"opt-bisect", cl::Hidden, cl::Optional,
cl::cb<void, const std::string &>([](const std::string &RangeStr) {
+ if (RangeStr == "-1") {
+ // -1 means run all passes
+ getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
+ return;
+ }
+
auto Ranges = RangeUtils::parseRanges(RangeStr);
if (!Ranges) {
handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
@@ -70,7 +79,7 @@ static cl::opt<std::string> OptBisectRanges(
getOptBisector().setRanges(std::move(*Ranges));
}),
cl::desc("Run optimization passes only for the specified ranges. "
- "Format: '1-10,20-30,45' (runs passes 1-10, 20-30, and 45)"));
+ "Format: '1-10,20-30,45' (runs passes 1-10, 20-30, and 45). Pass '0' to run no passes and -1 to run all passes."));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
diff --git a/llvm/test/Other/opt-bisect-ranges.ll b/llvm/test/Other/opt-bisect-ranges.ll
index 145cf169ca370..5f48aa963290c 100644
--- a/llvm/test/Other/opt-bisect-ranges.ll
+++ b/llvm/test/Other/opt-bisect-ranges.ll
@@ -20,6 +20,24 @@
; CHECK-SINGLE: BISECT: running pass (5) simplifycfg on foo
; CHECK-SINGLE: BISECT: NOT running pass (6) sroa on foo
+; Test running no passes
+; RUN: opt -O1 -opt-bisect=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+; CHECK-NONE: BISECT: NOT running pass (1) annotation2metadata on [module]
+; CHECK-NONE: BISECT: NOT running pass (2) forceattrs on [module]
+; CHECK-NONE: BISECT: NOT running pass (3) inferattrs on [module]
+; CHECK-NONE: BISECT: NOT running pass (4) lower-expect on foo
+; CHECK-NONE: BISECT: NOT running pass (5) simplifycfg on foo
+; CHECK-NONE: BISECT: NOT running pass (6) sroa on foo
+
+; Test running all passes
+; RUN: opt -O1 -opt-bisect=-1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-ALL
+; CHECK-ALL: BISECT: running pass (1) annotation2metadata on [module]
+; CHECK-ALL: BISECT: running pass (2) forceattrs on [module]
+; CHECK-ALL: BISECT: running pass (3) inferattrs on [module]
+; CHECK-ALL: BISECT: running pass (4) lower-expect on foo
+; CHECK-ALL: BISECT: running pass (5) simplifycfg on foo
+; CHECK-ALL: BISECT: running pass (6) sroa on foo
+
; Test backward compatibility: -opt-bisect-limit=3 should be equivalent to -opt-bisect=1-3
; RUN: opt -O1 -opt-bisect-limit=3 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIMIT
; CHECK-LIMIT: BISECT: running pass (1) annotation2metadata on [module]
>From 4d95e9c942d3e7456f12cdcdb91f9b2b52b772be Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 19:58:35 +0000
Subject: [PATCH 24/49] comment change
---
llvm/lib/IR/OptBisect.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 4bf920a40879c..46092670fa07b 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -79,7 +79,7 @@ static cl::opt<std::string> OptBisectRanges(
getOptBisector().setRanges(std::move(*Ranges));
}),
cl::desc("Run optimization passes only for the specified ranges. "
- "Format: '1-10,20-30,45' (runs passes 1-10, 20-30, and 45). Pass '0' to run no passes and -1 to run all passes."));
+ "Format: '1-10,20-30,45' runs passes 1-10, 20-30, and 45, where index 1 is the first pass. Supply '0' to run no passes and -1 to run all passes."));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
>From eb4bb4e89a54b413ac6dfcf0225d79b93be507f9 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 4 Sep 2025 19:58:49 +0000
Subject: [PATCH 25/49] format
---
llvm/lib/IR/OptBisect.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 46092670fa07b..8add03d957f24 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -79,7 +79,9 @@ static cl::opt<std::string> OptBisectRanges(
getOptBisector().setRanges(std::move(*Ranges));
}),
cl::desc("Run optimization passes only for the specified ranges. "
- "Format: '1-10,20-30,45' runs passes 1-10, 20-30, and 45, where index 1 is the first pass. Supply '0' to run no passes and -1 to run all passes."));
+ "Format: '1-10,20-30,45' runs passes 1-10, 20-30, and 45, where "
+ "index 1 is the first pass. Supply '0' to run no passes and -1 to "
+ "run all passes."));
static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
>From 635313168a2abde6968dd24c78d0585583bdcd72 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 20:18:50 +0000
Subject: [PATCH 26/49] cleanup
---
llvm/include/llvm/Support/Range.h | 30 +++++++----------
llvm/lib/IR/OptBisect.cpp | 21 ++++--------
llvm/lib/Support/Range.cpp | 48 +++++-----------------------
llvm/test/Other/opt-bisect-ranges.ll | 10 +++---
llvm/unittests/Support/RangeTest.cpp | 8 -----
5 files changed, 32 insertions(+), 85 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 7f093d7efb631..0714d26b963bc 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
+#include <cassert>
#include <cstdint>
namespace llvm {
@@ -26,16 +27,18 @@ class raw_ostream;
namespace llvm {
-/// Represents a range of integers [Begin, End] (inclusive on both ends)
+/// Represents a range of integers [Begin, End], inclusive on both ends, where Begin <= End.
struct Range {
int64_t Begin;
int64_t End;
- Range(const int64_t Begin, const int64_t End) : Begin(Begin), End(End) {}
- Range(const int64_t Single) : Begin(Single), End(Single) {}
+ Range(int64_t Begin, int64_t End) : Begin(Begin), End(End) {
+ assert(Begin <= End && "Range Begin must be <= End");
+ }
+ Range(int64_t Single) : Begin(Single), End(Single) {}
/// Check if the given value is within this range (inclusive)
- bool contains(const int64_t Value) const {
+ bool contains(int64_t Value) const {
return Value >= Begin && Value <= End;
}
@@ -69,27 +72,18 @@ class RangeUtils {
/// \param Separator The separator character to use (',' or ':')
/// \returns Expected<RangeList> containing the parsed ranges on success,
/// or an Error on failure
- static Expected<RangeList> parseRanges(const StringRef RangeStr,
- const char Separator = ',');
-
- /// Legacy interface for backward compatibility.
- /// \deprecated Use the Expected<RangeList> version instead
- static bool parseRanges(const StringRef RangeStr, RangeList &Ranges,
- const char Separator = ',');
+ static Expected<RangeList> parseRanges(StringRef RangeStr,
+ char Separator = ',');
/// Check if a value is contained in any of the ranges
- static bool contains(const ArrayRef<Range> Ranges, const int64_t Value);
-
- /// Convert ranges back to string representation for debugging
- static std::string rangesToString(const ArrayRef<Range> Ranges,
- const char Separator = ',');
+ static bool contains(ArrayRef<Range> Ranges, int64_t Value);
/// Print ranges to output stream
- static void printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges);
+ static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges);
/// Merge adjacent/consecutive ranges into single ranges
/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10]
- static RangeList mergeAdjacentRanges(const ArrayRef<Range> Ranges);
+ static RangeList mergeAdjacentRanges(ArrayRef<Range> Ranges);
};
} // end namespace llvm
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 8add03d957f24..964964999abd4 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -36,25 +36,18 @@ static OptDisable &getOptDisabler() {
static cl::opt<int> OptBisectLimit(
"opt-bisect-limit", cl::Hidden, cl::init(-1), cl::Optional,
cl::cb<void, int>([](int Limit) {
- if (Limit == -1) {
+ if (Limit == -1)
// -1 means run all passes
getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
- } else if (Limit == 0) {
+ else if (Limit == 0)
// 0 means run no passes
getOptBisector().setRanges({{0, 0}});
- } else if (Limit > 0) {
+ else if (Limit > 0)
// Convert limit to range 1-Limit
- std::string RangeStr = Limit == 1 ? "1" : "1-" + llvm::utostr(Limit);
- auto Ranges = RangeUtils::parseRanges(RangeStr);
- if (!Ranges) {
- handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
- errs() << "Error: Invalid limit for -opt-bisect-limit: " << Limit
- << " (" << E.getMessage() << ")\n";
- });
- exit(1);
- }
- getOptBisector().setRanges(std::move(*Ranges));
- }
+ getOptBisector().setRanges({{1, Limit}});
+ else
+ llvm_unreachable(
+ ("Invalid limit for -opt-bisect-limit: " + llvm::utostr(Limit)).c_str());
}),
cl::desc(
"Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index f2567970c6670..bdc7e50171898 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Range.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
@@ -14,21 +15,17 @@
using namespace llvm;
-Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
- const char Separator) {
+Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
+ char Separator) {
RangeList Ranges;
if (Str.empty())
return std::move(Ranges);
- // Split by the specified separator
- SmallVector<StringRef, 8> Parts;
- Str.split(Parts, Separator, -1, false);
-
// Regex to match either single number or range "num1-num2"
const Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
- for (StringRef Part : Parts) {
+ for (StringRef Part : llvm::split(Str, Separator)) {
Part = Part.trim();
if (Part.empty())
continue;
@@ -68,24 +65,10 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(const StringRef Str,
Ranges.push_back(Range(Begin, End));
}
- return std::move(Ranges);
-}
-
-bool RangeUtils::parseRanges(const StringRef Str, RangeList &Ranges,
- const char Separator) {
- auto ExpectedRanges = parseRanges(Str, Separator);
- if (!ExpectedRanges) {
- // For backward compatibility, print error to stderr
- handleAllErrors(ExpectedRanges.takeError(), [](const StringError &E) {
- errs() << E.getMessage() << "\n";
- });
- return false;
- }
- Ranges = std::move(*ExpectedRanges);
- return true;
+ return Ranges;
}
-bool RangeUtils::contains(const ArrayRef<Range> Ranges, const int64_t Value) {
+bool RangeUtils::contains(ArrayRef<Range> Ranges, int64_t Value) {
for (const Range &R : Ranges) {
if (R.contains(Value))
return true;
@@ -93,22 +76,7 @@ bool RangeUtils::contains(const ArrayRef<Range> Ranges, const int64_t Value) {
return false;
}
-std::string RangeUtils::rangesToString(const ArrayRef<Range> Ranges,
- const char Separator) {
- std::ostringstream OS;
- for (size_t I = 0; I < Ranges.size(); ++I) {
- if (I > 0)
- OS << Separator;
- const Range &R = Ranges[I];
- if (R.Begin == R.End)
- OS << R.Begin;
- else
- OS << R.Begin << "-" << R.End;
- }
- return OS.str();
-}
-
-void RangeUtils::printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges) {
+void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges) {
if (Ranges.empty())
OS << "empty";
else {
@@ -128,7 +96,7 @@ void RangeUtils::printRanges(raw_ostream &OS, const ArrayRef<Range> Ranges) {
}
RangeUtils::RangeList
-RangeUtils::mergeAdjacentRanges(const ArrayRef<Range> Ranges) {
+RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
if (Ranges.empty())
return {};
diff --git a/llvm/test/Other/opt-bisect-ranges.ll b/llvm/test/Other/opt-bisect-ranges.ll
index 5f48aa963290c..5cdfba699e28e 100644
--- a/llvm/test/Other/opt-bisect-ranges.ll
+++ b/llvm/test/Other/opt-bisect-ranges.ll
@@ -1,7 +1,7 @@
; Test that verifies functionality for -opt-bisect with range specifications
; Test basic range functionality: run passes 1-3 and 7-8
-; RUN: opt -O1 -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-RANGES
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-RANGES
; CHECK-RANGES: BISECT: running pass (1) annotation2metadata on [module]
; CHECK-RANGES: BISECT: running pass (2) forceattrs on [module]
; CHECK-RANGES: BISECT: running pass (3) inferattrs on [module]
@@ -12,7 +12,7 @@
; CHECK-RANGES: BISECT: running pass (8) openmp-opt on [module]
; Test single pass selection: run only pass 5
-; RUN: opt -O1 -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE
; CHECK-SINGLE: BISECT: NOT running pass (1) annotation2metadata on [module]
; CHECK-SINGLE: BISECT: NOT running pass (2) forceattrs on [module]
; CHECK-SINGLE: BISECT: NOT running pass (3) inferattrs on [module]
@@ -21,7 +21,7 @@
; CHECK-SINGLE: BISECT: NOT running pass (6) sroa on foo
; Test running no passes
-; RUN: opt -O1 -opt-bisect=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
; CHECK-NONE: BISECT: NOT running pass (1) annotation2metadata on [module]
; CHECK-NONE: BISECT: NOT running pass (2) forceattrs on [module]
; CHECK-NONE: BISECT: NOT running pass (3) inferattrs on [module]
@@ -30,7 +30,7 @@
; CHECK-NONE: BISECT: NOT running pass (6) sroa on foo
; Test running all passes
-; RUN: opt -O1 -opt-bisect=-1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-ALL
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=-1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-ALL
; CHECK-ALL: BISECT: running pass (1) annotation2metadata on [module]
; CHECK-ALL: BISECT: running pass (2) forceattrs on [module]
; CHECK-ALL: BISECT: running pass (3) inferattrs on [module]
@@ -39,7 +39,7 @@
; CHECK-ALL: BISECT: running pass (6) sroa on foo
; Test backward compatibility: -opt-bisect-limit=3 should be equivalent to -opt-bisect=1-3
-; RUN: opt -O1 -opt-bisect-limit=3 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIMIT
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect-limit=3 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIMIT
; CHECK-LIMIT: BISECT: running pass (1) annotation2metadata on [module]
; CHECK-LIMIT: BISECT: running pass (2) forceattrs on [module]
; CHECK-LIMIT: BISECT: running pass (3) inferattrs on [module]
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 94fc281386cdd..17f215049e387 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -127,14 +127,6 @@ TEST(RangeUtilsTest, Contains) {
EXPECT_FALSE(RangeUtils::contains(Ranges, 21));
}
-TEST(RangeUtilsTest, RangesToString) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
-
- std::string Result = RangeUtils::rangesToString(Ranges);
- EXPECT_EQ(Result, "1-5,10,15-20");
-}
-
TEST(RangeUtilsTest, SeparatorParameter) {
RangeUtils::RangeList ColonRanges, CommaRanges;
>From 67daab44965acff0bb9a4cb45dbd49f3dd2e2cb5 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 20:21:16 +0000
Subject: [PATCH 27/49] format
---
llvm/include/llvm/Support/Range.h | 7 +++----
llvm/lib/IR/OptBisect.cpp | 3 ++-
llvm/lib/Support/Range.cpp | 3 +--
llvm/test/Other/opt-bisect-ranges.ll | 15 ++++++++++-----
4 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 0714d26b963bc..c785546640f36 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -27,7 +27,8 @@ class raw_ostream;
namespace llvm {
-/// Represents a range of integers [Begin, End], inclusive on both ends, where Begin <= End.
+/// Represents a range of integers [Begin, End], inclusive on both ends, where
+/// Begin <= End.
struct Range {
int64_t Begin;
int64_t End;
@@ -38,9 +39,7 @@ struct Range {
Range(int64_t Single) : Begin(Single), End(Single) {}
/// Check if the given value is within this range (inclusive)
- bool contains(int64_t Value) const {
- return Value >= Begin && Value <= End;
- }
+ bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
/// Check if this range overlaps with another range
bool overlaps(const Range &Other) const {
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 964964999abd4..0523d1450751e 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -47,7 +47,8 @@ static cl::opt<int> OptBisectLimit(
getOptBisector().setRanges({{1, Limit}});
else
llvm_unreachable(
- ("Invalid limit for -opt-bisect-limit: " + llvm::utostr(Limit)).c_str());
+ ("Invalid limit for -opt-bisect-limit: " + llvm::utostr(Limit))
+ .c_str());
}),
cl::desc(
"Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index bdc7e50171898..76cacb26b10b4 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -95,8 +95,7 @@ void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges) {
}
}
-RangeUtils::RangeList
-RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
+RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
if (Ranges.empty())
return {};
diff --git a/llvm/test/Other/opt-bisect-ranges.ll b/llvm/test/Other/opt-bisect-ranges.ll
index 5cdfba699e28e..84b2d336f6f6e 100644
--- a/llvm/test/Other/opt-bisect-ranges.ll
+++ b/llvm/test/Other/opt-bisect-ranges.ll
@@ -1,7 +1,8 @@
; Test that verifies functionality for -opt-bisect with range specifications
; Test basic range functionality: run passes 1-3 and 7-8
-; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-RANGES
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
+; RUN: -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-RANGES
; CHECK-RANGES: BISECT: running pass (1) annotation2metadata on [module]
; CHECK-RANGES: BISECT: running pass (2) forceattrs on [module]
; CHECK-RANGES: BISECT: running pass (3) inferattrs on [module]
@@ -12,7 +13,8 @@
; CHECK-RANGES: BISECT: running pass (8) openmp-opt on [module]
; Test single pass selection: run only pass 5
-; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
+; RUN: -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE
; CHECK-SINGLE: BISECT: NOT running pass (1) annotation2metadata on [module]
; CHECK-SINGLE: BISECT: NOT running pass (2) forceattrs on [module]
; CHECK-SINGLE: BISECT: NOT running pass (3) inferattrs on [module]
@@ -21,7 +23,8 @@
; CHECK-SINGLE: BISECT: NOT running pass (6) sroa on foo
; Test running no passes
-; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
+; RUN: -opt-bisect=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
; CHECK-NONE: BISECT: NOT running pass (1) annotation2metadata on [module]
; CHECK-NONE: BISECT: NOT running pass (2) forceattrs on [module]
; CHECK-NONE: BISECT: NOT running pass (3) inferattrs on [module]
@@ -30,7 +33,8 @@
; CHECK-NONE: BISECT: NOT running pass (6) sroa on foo
; Test running all passes
-; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect=-1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-ALL
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
+; RUN: -opt-bisect=-1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-ALL
; CHECK-ALL: BISECT: running pass (1) annotation2metadata on [module]
; CHECK-ALL: BISECT: running pass (2) forceattrs on [module]
; CHECK-ALL: BISECT: running pass (3) inferattrs on [module]
@@ -39,7 +43,8 @@
; CHECK-ALL: BISECT: running pass (6) sroa on foo
; Test backward compatibility: -opt-bisect-limit=3 should be equivalent to -opt-bisect=1-3
-; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' -opt-bisect-limit=3 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIMIT
+; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
+; RUN: -opt-bisect-limit=3 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LIMIT
; CHECK-LIMIT: BISECT: running pass (1) annotation2metadata on [module]
; CHECK-LIMIT: BISECT: running pass (2) forceattrs on [module]
; CHECK-LIMIT: BISECT: running pass (3) inferattrs on [module]
>From 81a3379a6e4b304d6e98cb1f210e302fde26b163 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 20:47:49 +0000
Subject: [PATCH 28/49] more cleanup
---
llvm/include/llvm/IR/OptBisect.h | 2 +-
llvm/include/llvm/Support/Range.h | 39 ++++++----
llvm/lib/Support/DebugCounter.cpp | 2 +-
llvm/lib/Support/Range.cpp | 24 +++---
llvm/unittests/Support/RangeTest.cpp | 109 ++++++++++++++++-----------
5 files changed, 98 insertions(+), 78 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 0c5c57b1771e0..e051b7960cd49 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -71,7 +71,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// isEnabled() should return true before calling shouldRunPass().
bool isEnabled() const override { return !BisectRanges.empty(); }
- /// Set ranges directly from a RangeList
+ /// Set ranges directly from a RangeList.
void setRanges(RangeUtils::RangeList Ranges) {
BisectRanges = std::move(Ranges);
}
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index c785546640f36..67bdf56da1f64 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -33,55 +33,62 @@ struct Range {
int64_t Begin;
int64_t End;
+ /// Create a range [Begin, End].
Range(int64_t Begin, int64_t End) : Begin(Begin), End(End) {
assert(Begin <= End && "Range Begin must be <= End");
}
+ /// Create a range [Single, Single].
Range(int64_t Single) : Begin(Single), End(Single) {}
- /// Check if the given value is within this range (inclusive)
+ /// Check if the given value is within this range (inclusive).
bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
- /// Check if this range overlaps with another range
+ /// Check if this range overlaps with another range.
bool overlaps(const Range &Other) const {
return Begin <= Other.End && End >= Other.Begin;
}
- /// Get the size of this range
+ /// Get the size of this range.
int64_t size() const { return End - Begin + 1; }
- std::string toString() const {
- return std::to_string(Begin) + "-" + std::to_string(End);
+ /// Print the range to the output stream.
+ void print(raw_ostream &OS) const {
+ if (Begin == End)
+ OS << Begin;
+ else
+ OS << Begin << "-" << End;
}
- void print(raw_ostream &OS) const { OS << Begin << "-" << End; }
-
bool operator==(const Range &Other) const {
return Begin == Other.Begin && End == Other.End;
}
};
-/// Utility class for parsing and managing range specifications
+/// Utility class for parsing and managing range specifications.
class RangeUtils {
public:
using RangeList = SmallVector<Range, 8>;
/// Parse a range specification string like "1-10,20-30,45" or
/// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping.
- /// \param RangeStr The string to parse
- /// \param Separator The separator character to use (',' or ':')
+ /// \param RangeStr The string to parse.
+ /// \param Separator The separator character to use (',' or ':').
/// \returns Expected<RangeList> containing the parsed ranges on success,
- /// or an Error on failure
+ /// or an Error on failure.
static Expected<RangeList> parseRanges(StringRef RangeStr,
char Separator = ',');
- /// Check if a value is contained in any of the ranges
+ /// Check if a value is contained in any of the ranges.
static bool contains(ArrayRef<Range> Ranges, int64_t Value);
- /// Print ranges to output stream
- static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges);
+ /// Print ranges to output stream.
+ /// \param OS The output stream to print to.
+ /// \param Ranges The ranges to print.
+ /// \param Separator The separator character to use between ranges (i.e. ',' or ':').
+ static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges, char Separator = ',');
- /// Merge adjacent/consecutive ranges into single ranges
- /// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10]
+ /// Merge adjacent/consecutive ranges into single ranges.
+ /// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
static RangeList mergeAdjacentRanges(ArrayRef<Range> Ranges);
};
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 350629415ffd6..31d1192eb3b1f 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -11,7 +11,7 @@ using namespace llvm;
namespace llvm {
void DebugCounter::printChunks(raw_ostream &OS, ArrayRef<Range> Ranges) {
- RangeUtils::printRanges(OS, Ranges);
+ RangeUtils::printRanges(OS, Ranges, ':');
}
} // namespace llvm
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index 76cacb26b10b4..09bdc567597aa 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -22,7 +22,7 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
if (Str.empty())
return std::move(Ranges);
- // Regex to match either single number or range "num1-num2"
+ // Regex to match either single number or range "num1-num2".
const Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
for (StringRef Part : llvm::split(Str, Separator)) {
@@ -43,7 +43,7 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
Matches[1].str().c_str());
if (!Matches[3].empty()) {
- // Range format "begin-end"
+ // Range format "begin-end".
if (Matches[3].getAsInteger(10, End))
return createStringError(std::errc::invalid_argument,
"Failed to parse number: '%s'",
@@ -52,10 +52,10 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
return createStringError(std::errc::invalid_argument,
"Invalid range: %lld >= %lld", Begin, End);
} else
- // Single number
+ // Single number.
End = Begin;
- // Check ordering constraint (ranges must be in increasing order)
+ // Check ordering constraint (ranges must be in increasing order).
if (!Ranges.empty() && Begin <= Ranges.back().End)
return createStringError(
std::errc::invalid_argument,
@@ -76,21 +76,17 @@ bool RangeUtils::contains(ArrayRef<Range> Ranges, int64_t Value) {
return false;
}
-void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges) {
+void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges, char Separator) {
if (Ranges.empty())
OS << "empty";
else {
bool IsFirst = true;
for (const Range &R : Ranges) {
if (!IsFirst)
- OS << ':';
+ OS << Separator;
else
IsFirst = false;
-
- if (R.Begin == R.End)
- OS << R.Begin;
- else
- OS << R.Begin << "-" << R.End;
+ R.print(OS);
}
}
}
@@ -106,12 +102,12 @@ RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
const Range &Current = Ranges[I];
Range &Last = Result.back();
- // Check if current range is adjacent to the last merged range
+ // Check if current range is adjacent to the last merged range.
if (Current.Begin == Last.End + 1) {
- // Merge by extending the end of the last range
+ // Merge by extending the end of the last range.
Last.End = Current.End;
} else {
- // Not adjacent, add as separate range
+ // Not adjacent, add as separate range.
Result.push_back(Current);
}
}
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 17f215049e387..6140dbbd125e4 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -46,27 +46,30 @@ TEST(RangeTest, RangeOverlaps) {
}
TEST(RangeUtilsTest, ParseSingleNumber) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("42", Ranges));
+ auto ER = RangeUtils::parseRanges("42");
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 1U);
EXPECT_EQ(Ranges[0].Begin, 42);
EXPECT_EQ(Ranges[0].End, 42);
}
TEST(RangeUtilsTest, ParseSingleRange) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("10-20", Ranges));
+ auto ER = RangeUtils::parseRanges("10-20");
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 1U);
EXPECT_EQ(Ranges[0].Begin, 10);
EXPECT_EQ(Ranges[0].End, 20);
}
TEST(RangeUtilsTest, ParseMultipleRanges) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ auto ER = RangeUtils::parseRanges("1-5,10,15-20");
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
- // Ranges are in input order (DebugCounter style)
+ // Ranges are in input order (DebugCounter style).
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
EXPECT_EQ(Ranges[1].Begin, 10);
@@ -76,8 +79,9 @@ TEST(RangeUtilsTest, ParseMultipleRanges) {
}
TEST(RangeUtilsTest, ParseColonSeparated) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", Ranges, ':'));
+ auto ER = RangeUtils::parseRanges("1-5:10:15-20", ':');
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
@@ -88,29 +92,37 @@ TEST(RangeUtilsTest, ParseColonSeparated) {
}
TEST(RangeUtilsTest, ParseEmptyString) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("", Ranges));
+ auto ER = RangeUtils::parseRanges("");
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_TRUE(Ranges.empty());
}
TEST(RangeUtilsTest, ParseInvalidRanges) {
- RangeUtils::RangeList Ranges;
-
- // Invalid number
- EXPECT_FALSE(RangeUtils::parseRanges("abc", Ranges));
-
- // Invalid range (begin > end)
- EXPECT_FALSE(RangeUtils::parseRanges("10-5", Ranges));
-
- // Out of order ranges (DebugCounter constraint)
- EXPECT_FALSE(RangeUtils::parseRanges("10,5", Ranges));
- EXPECT_FALSE(
- RangeUtils::parseRanges("1-5,3-7", Ranges)); // Overlapping not allowed
+ // Invalid number.
+ auto ER1 = RangeUtils::parseRanges("abc");
+ EXPECT_FALSE(ER1);
+ consumeError(ER1.takeError());
+
+ // Invalid range (begin > end).
+ auto ER2 = RangeUtils::parseRanges("10-5");
+ EXPECT_FALSE(ER2);
+ consumeError(ER2.takeError());
+
+ // Out of order ranges (DebugCounter constraint and overlap).
+ auto ER3 = RangeUtils::parseRanges("10,5");
+ EXPECT_FALSE(ER3);
+ consumeError(ER3.takeError());
+
+ auto ER4 = RangeUtils::parseRanges("1-5,3-7");
+ EXPECT_FALSE(ER4);
+ consumeError(ER4.takeError());
}
TEST(RangeUtilsTest, Contains) {
- RangeUtils::RangeList Ranges;
- EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ auto ER = RangeUtils::parseRanges("1-5,10,15-20");
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_TRUE(RangeUtils::contains(Ranges, 1));
EXPECT_TRUE(RangeUtils::contains(Ranges, 3));
@@ -130,9 +142,14 @@ TEST(RangeUtilsTest, Contains) {
TEST(RangeUtilsTest, SeparatorParameter) {
RangeUtils::RangeList ColonRanges, CommaRanges;
- // Test explicit separator parameters
- EXPECT_TRUE(RangeUtils::parseRanges("1-5:10:15-20", ColonRanges, ':'));
- EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", CommaRanges, ','));
+ // Test explicit separator parameters.
+ auto ERC = RangeUtils::parseRanges("1-5:10:15-20", ':');
+ ASSERT_TRUE(ERC);
+ ColonRanges = std::move(*ERC);
+
+ auto ERM = RangeUtils::parseRanges("1-5,10,15-20", ',');
+ ASSERT_TRUE(ERM);
+ CommaRanges = std::move(*ERM);
EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
for (size_t I = 0; I < ColonRanges.size(); ++I) {
@@ -140,7 +157,7 @@ TEST(RangeUtilsTest, SeparatorParameter) {
EXPECT_EQ(ColonRanges[I].End, CommaRanges[I].End);
}
- // Test that both work with contains()
+ // Test that both work with contains().
EXPECT_TRUE(RangeUtils::contains(ColonRanges, 3));
EXPECT_TRUE(RangeUtils::contains(CommaRanges, 3));
EXPECT_TRUE(RangeUtils::contains(ColonRanges, 10));
@@ -153,10 +170,10 @@ TEST(RangeUtilsTest, SeparatorParameter) {
}
TEST(RangeUtilsTest, DefaultCommaSeparator) {
- RangeUtils::RangeList Ranges;
-
- // Test that comma is the default separator
- EXPECT_TRUE(RangeUtils::parseRanges("1-5,10,15-20", Ranges));
+ // Test that comma is the default separator.
+ auto ER = RangeUtils::parseRanges("1-5,10,15-20");
+ ASSERT_TRUE(ER);
+ auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
EXPECT_EQ(Ranges[0].End, 5);
@@ -173,13 +190,13 @@ TEST(RangeTest, MergeAdjacentRanges) {
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_TRUE(Result.empty());
- // Single range - no change
+ // Single range - no change.
Input.push_back(Range(5, 10));
Expected.push_back(Range(5, 10));
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
- // Adjacent ranges should merge
+ // Adjacent ranges should merge.
Input.clear();
Expected.clear();
Input.push_back(Range(1, 3));
@@ -189,32 +206,32 @@ TEST(RangeTest, MergeAdjacentRanges) {
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
- // Non-adjacent ranges should not merge
+ // Non-adjacent ranges should not merge.
Input.clear();
Expected.clear();
Input.push_back(Range(1, 3));
- Input.push_back(Range(5, 7)); // Gap between 3 and 5
- Input.push_back(Range(10, 12)); // Gap between 7 and 10
+ Input.push_back(Range(5, 7)); // Gap between 3 and 5.
+ Input.push_back(Range(10, 12)); // Gap between 7 and 10.
Expected.push_back(Range(1, 3));
Expected.push_back(Range(5, 7));
Expected.push_back(Range(10, 12));
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
- // Mixed adjacent and non-adjacent
+ // Mixed adjacent and non-adjacent.
Input.clear();
Expected.clear();
Input.push_back(Range(1, 3));
- Input.push_back(Range(4, 6)); // Adjacent to first
- Input.push_back(Range(8, 10)); // Gap
- Input.push_back(Range(11, 13)); // Adjacent to third
- Input.push_back(Range(14, 16)); // Adjacent to fourth
- Expected.push_back(Range(1, 6)); // Merged 1-3 and 4-6
- Expected.push_back(Range(8, 16)); // Merged 8-10, 11-13, 14-16
+ Input.push_back(Range(4, 6)); // Adjacent to first.
+ Input.push_back(Range(8, 10)); // Gap.
+ Input.push_back(Range(11, 13)); // Adjacent to third.
+ Input.push_back(Range(14, 16)); // Adjacent to fourth.
+ Expected.push_back(Range(1, 6)); // Merged 1-3 and 4-6.
+ Expected.push_back(Range(8, 16)); // Merged 8-10, 11-13, 14-16.
Result = RangeUtils::mergeAdjacentRanges(Input);
EXPECT_EQ(Expected, Result);
- // Single numbers that are adjacent
+ // Single numbers that are adjacent.
Input.clear();
Expected.clear();
Input.push_back(Range(5));
>From ac333feade32d32b4fa5512eadef9e66a2485e17 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 20:47:59 +0000
Subject: [PATCH 29/49] format
---
llvm/include/llvm/Support/Range.h | 6 ++++--
llvm/lib/Support/Range.cpp | 3 ++-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 67bdf56da1f64..3d6d08bec27e6 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -84,8 +84,10 @@ class RangeUtils {
/// Print ranges to output stream.
/// \param OS The output stream to print to.
/// \param Ranges The ranges to print.
- /// \param Separator The separator character to use between ranges (i.e. ',' or ':').
- static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges, char Separator = ',');
+ /// \param Separator The separator character to use between ranges (i.e. ','
+ /// or ':').
+ static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges,
+ char Separator = ',');
/// Merge adjacent/consecutive ranges into single ranges.
/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index 09bdc567597aa..a3f52fc73b89d 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -76,7 +76,8 @@ bool RangeUtils::contains(ArrayRef<Range> Ranges, int64_t Value) {
return false;
}
-void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges, char Separator) {
+void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges,
+ char Separator) {
if (Ranges.empty())
OS << "empty";
else {
>From e8531a82621510193b0b23f3a307d5725a7905c6 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 20:54:55 +0000
Subject: [PATCH 30/49] range test cleanup
---
llvm/unittests/Support/RangeTest.cpp | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 6140dbbd125e4..f10038c759f78 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -8,6 +8,7 @@
#include "llvm/Support/Range.h"
#include "gtest/gtest.h"
+#include "llvm/Testing/Support/Error.h"
using namespace llvm;
@@ -47,7 +48,7 @@ TEST(RangeTest, RangeOverlaps) {
TEST(RangeUtilsTest, ParseSingleNumber) {
auto ER = RangeUtils::parseRanges("42");
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 1U);
EXPECT_EQ(Ranges[0].Begin, 42);
@@ -56,7 +57,7 @@ TEST(RangeUtilsTest, ParseSingleNumber) {
TEST(RangeUtilsTest, ParseSingleRange) {
auto ER = RangeUtils::parseRanges("10-20");
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 1U);
EXPECT_EQ(Ranges[0].Begin, 10);
@@ -65,7 +66,7 @@ TEST(RangeUtilsTest, ParseSingleRange) {
TEST(RangeUtilsTest, ParseMultipleRanges) {
auto ER = RangeUtils::parseRanges("1-5,10,15-20");
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
@@ -80,7 +81,7 @@ TEST(RangeUtilsTest, ParseMultipleRanges) {
TEST(RangeUtilsTest, ParseColonSeparated) {
auto ER = RangeUtils::parseRanges("1-5:10:15-20", ':');
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
@@ -93,7 +94,7 @@ TEST(RangeUtilsTest, ParseColonSeparated) {
TEST(RangeUtilsTest, ParseEmptyString) {
auto ER = RangeUtils::parseRanges("");
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_TRUE(Ranges.empty());
}
@@ -101,27 +102,27 @@ TEST(RangeUtilsTest, ParseEmptyString) {
TEST(RangeUtilsTest, ParseInvalidRanges) {
// Invalid number.
auto ER1 = RangeUtils::parseRanges("abc");
- EXPECT_FALSE(ER1);
+ EXPECT_THAT_EXPECTED(ER1, Failed());
consumeError(ER1.takeError());
// Invalid range (begin > end).
auto ER2 = RangeUtils::parseRanges("10-5");
- EXPECT_FALSE(ER2);
+ EXPECT_THAT_EXPECTED(ER2, Failed());
consumeError(ER2.takeError());
// Out of order ranges (DebugCounter constraint and overlap).
auto ER3 = RangeUtils::parseRanges("10,5");
- EXPECT_FALSE(ER3);
+ EXPECT_THAT_EXPECTED(ER3, Failed());
consumeError(ER3.takeError());
auto ER4 = RangeUtils::parseRanges("1-5,3-7");
- EXPECT_FALSE(ER4);
+ EXPECT_THAT_EXPECTED(ER4, Failed());
consumeError(ER4.takeError());
}
TEST(RangeUtilsTest, Contains) {
auto ER = RangeUtils::parseRanges("1-5,10,15-20");
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_TRUE(RangeUtils::contains(Ranges, 1));
@@ -144,11 +145,11 @@ TEST(RangeUtilsTest, SeparatorParameter) {
// Test explicit separator parameters.
auto ERC = RangeUtils::parseRanges("1-5:10:15-20", ':');
- ASSERT_TRUE(ERC);
+ ASSERT_THAT_EXPECTED(ERC, Succeeded());
ColonRanges = std::move(*ERC);
auto ERM = RangeUtils::parseRanges("1-5,10,15-20", ',');
- ASSERT_TRUE(ERM);
+ ASSERT_THAT_EXPECTED(ERM, Succeeded());
CommaRanges = std::move(*ERM);
EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
@@ -172,7 +173,7 @@ TEST(RangeUtilsTest, SeparatorParameter) {
TEST(RangeUtilsTest, DefaultCommaSeparator) {
// Test that comma is the default separator.
auto ER = RangeUtils::parseRanges("1-5,10,15-20");
- ASSERT_TRUE(ER);
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
EXPECT_EQ(Ranges[0].Begin, 1);
>From 78309327053588cd6e3be587c1da20bd1c5d76cc Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 20:55:06 +0000
Subject: [PATCH 31/49] format
---
llvm/unittests/Support/RangeTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index f10038c759f78..75c381342ef26 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Range.h"
-#include "gtest/gtest.h"
#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
using namespace llvm;
>From bde2225ca0a349af26ed1172ae04519c512a1f81 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 21:10:00 +0000
Subject: [PATCH 32/49] move range from struct -> class
---
llvm/include/llvm/Support/Range.h | 15 ++++-
llvm/lib/Support/DebugCounter.cpp | 6 +-
llvm/lib/Support/Range.cpp | 8 +--
.../reduce-chunk-list/reduce-chunk-list.cpp | 8 +--
llvm/unittests/Support/RangeTest.cpp | 56 +++++++++----------
5 files changed, 53 insertions(+), 40 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 3d6d08bec27e6..58dfc2637749d 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -29,10 +29,11 @@ namespace llvm {
/// Represents a range of integers [Begin, End], inclusive on both ends, where
/// Begin <= End.
-struct Range {
+class Range {
int64_t Begin;
int64_t End;
+public:
/// Create a range [Begin, End].
Range(int64_t Begin, int64_t End) : Begin(Begin), End(End) {
assert(Begin <= End && "Range Begin must be <= End");
@@ -40,6 +41,18 @@ struct Range {
/// Create a range [Single, Single].
Range(int64_t Single) : Begin(Single), End(Single) {}
+ int64_t getBegin() const { return Begin; }
+ int64_t getEnd() const { return End; }
+
+ void setBegin(int64_t NewBegin) {
+ assert(NewBegin <= End && "Range Begin must be <= End");
+ Begin = NewBegin;
+ }
+ void setEnd(int64_t NewEnd) {
+ assert(Begin <= NewEnd && "Range Begin must be <= End");
+ End = NewEnd;
+ }
+
/// Check if the given value is within this range (inclusive).
bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 31d1192eb3b1f..ed011b5d2d271 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -167,15 +167,15 @@ bool DebugCounter::handleCounterIncrement(CounterInfo &Info) {
bool Res = Info.Chunks[CurrIdx].contains(CurrCount);
if (BreakOnLast && CurrIdx == (Info.Chunks.size() - 1) &&
- CurrCount == Info.Chunks[CurrIdx].End) {
+ CurrCount == Info.Chunks[CurrIdx].getEnd()) {
LLVM_BUILTIN_DEBUGTRAP;
}
- if (CurrCount > Info.Chunks[CurrIdx].End) {
+ if (CurrCount > Info.Chunks[CurrIdx].getEnd()) {
Info.CurrChunkIdx++;
/// Handle consecutive blocks.
if (Info.CurrChunkIdx < Info.Chunks.size() &&
- CurrCount == Info.Chunks[Info.CurrChunkIdx].Begin)
+ CurrCount == Info.Chunks[Info.CurrChunkIdx].getBegin())
return true;
}
return Res;
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index a3f52fc73b89d..2fe00aa0234ab 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -56,11 +56,11 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
End = Begin;
// Check ordering constraint (ranges must be in increasing order).
- if (!Ranges.empty() && Begin <= Ranges.back().End)
+ if (!Ranges.empty() && Begin <= Ranges.back().getEnd())
return createStringError(
std::errc::invalid_argument,
"Expected ranges to be in increasing order: %lld <= %lld", Begin,
- Ranges.back().End);
+ Ranges.back().getEnd());
Ranges.push_back(Range(Begin, End));
}
@@ -104,9 +104,9 @@ RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
Range &Last = Result.back();
// Check if current range is adjacent to the last merged range.
- if (Current.Begin == Last.End + 1) {
+ if (Current.getBegin() == Last.getEnd() + 1) {
// Merge by extending the end of the last range.
- Last.End = Current.End;
+ Last.setEnd(Current.getEnd());
} else {
// Not adjacent, add as separate range.
Result.push_back(Current);
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index 50a8cb246d290..de41ca520c408 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -64,12 +64,12 @@ bool increaseGranularity(RangeUtils::RangeList &Chunks) {
bool SplitOne = false;
for (auto &C : Chunks) {
- if (C.Begin == C.End) {
+ if (C.getBegin() == C.getEnd()) {
NewChunks.push_back(C);
} else {
- int64_t Half = (C.Begin + C.End) / 2;
- NewChunks.push_back(Range(C.Begin, Half));
- NewChunks.push_back(Range(Half + 1, C.End));
+ int64_t Half = (C.getBegin() + C.getEnd()) / 2;
+ NewChunks.push_back(Range(C.getBegin(), Half));
+ NewChunks.push_back(Range(Half + 1, C.getEnd()));
SplitOne = true;
}
}
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 75c381342ef26..2127d5761c8e7 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -14,8 +14,8 @@ using namespace llvm;
TEST(RangeTest, BasicRange) {
Range R(5, 10);
- EXPECT_EQ(R.Begin, 5);
- EXPECT_EQ(R.End, 10);
+ EXPECT_EQ(R.getBegin(), 5);
+ EXPECT_EQ(R.getEnd(), 10);
EXPECT_TRUE(R.contains(5));
EXPECT_TRUE(R.contains(7));
EXPECT_TRUE(R.contains(10));
@@ -25,8 +25,8 @@ TEST(RangeTest, BasicRange) {
TEST(RangeTest, SingleValueRange) {
Range R(42);
- EXPECT_EQ(R.Begin, 42);
- EXPECT_EQ(R.End, 42);
+ EXPECT_EQ(R.getBegin(), 42);
+ EXPECT_EQ(R.getEnd(), 42);
EXPECT_TRUE(R.contains(42));
EXPECT_FALSE(R.contains(41));
EXPECT_FALSE(R.contains(43));
@@ -51,8 +51,8 @@ TEST(RangeUtilsTest, ParseSingleNumber) {
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 1U);
- EXPECT_EQ(Ranges[0].Begin, 42);
- EXPECT_EQ(Ranges[0].End, 42);
+ EXPECT_EQ(Ranges[0].getBegin(), 42);
+ EXPECT_EQ(Ranges[0].getEnd(), 42);
}
TEST(RangeUtilsTest, ParseSingleRange) {
@@ -60,8 +60,8 @@ TEST(RangeUtilsTest, ParseSingleRange) {
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 1U);
- EXPECT_EQ(Ranges[0].Begin, 10);
- EXPECT_EQ(Ranges[0].End, 20);
+ EXPECT_EQ(Ranges[0].getBegin(), 10);
+ EXPECT_EQ(Ranges[0].getEnd(), 20);
}
TEST(RangeUtilsTest, ParseMultipleRanges) {
@@ -71,12 +71,12 @@ TEST(RangeUtilsTest, ParseMultipleRanges) {
EXPECT_EQ(Ranges.size(), 3U);
// Ranges are in input order (DebugCounter style).
- EXPECT_EQ(Ranges[0].Begin, 1);
- EXPECT_EQ(Ranges[0].End, 5);
- EXPECT_EQ(Ranges[1].Begin, 10);
- EXPECT_EQ(Ranges[1].End, 10);
- EXPECT_EQ(Ranges[2].Begin, 15);
- EXPECT_EQ(Ranges[2].End, 20);
+ EXPECT_EQ(Ranges[0].getBegin(), 1);
+ EXPECT_EQ(Ranges[0].getEnd(), 5);
+ EXPECT_EQ(Ranges[1].getBegin(), 10);
+ EXPECT_EQ(Ranges[1].getEnd(), 10);
+ EXPECT_EQ(Ranges[2].getBegin(), 15);
+ EXPECT_EQ(Ranges[2].getEnd(), 20);
}
TEST(RangeUtilsTest, ParseColonSeparated) {
@@ -84,12 +84,12 @@ TEST(RangeUtilsTest, ParseColonSeparated) {
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
- EXPECT_EQ(Ranges[0].Begin, 1);
- EXPECT_EQ(Ranges[0].End, 5);
- EXPECT_EQ(Ranges[1].Begin, 10);
- EXPECT_EQ(Ranges[1].End, 10);
- EXPECT_EQ(Ranges[2].Begin, 15);
- EXPECT_EQ(Ranges[2].End, 20);
+ EXPECT_EQ(Ranges[0].getBegin(), 1);
+ EXPECT_EQ(Ranges[0].getEnd(), 5);
+ EXPECT_EQ(Ranges[1].getBegin(), 10);
+ EXPECT_EQ(Ranges[1].getEnd(), 10);
+ EXPECT_EQ(Ranges[2].getBegin(), 15);
+ EXPECT_EQ(Ranges[2].getEnd(), 20);
}
TEST(RangeUtilsTest, ParseEmptyString) {
@@ -154,8 +154,8 @@ TEST(RangeUtilsTest, SeparatorParameter) {
EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
for (size_t I = 0; I < ColonRanges.size(); ++I) {
- EXPECT_EQ(ColonRanges[I].Begin, CommaRanges[I].Begin);
- EXPECT_EQ(ColonRanges[I].End, CommaRanges[I].End);
+ EXPECT_EQ(ColonRanges[I].getBegin(), CommaRanges[I].getBegin());
+ EXPECT_EQ(ColonRanges[I].getEnd(), CommaRanges[I].getEnd());
}
// Test that both work with contains().
@@ -176,12 +176,12 @@ TEST(RangeUtilsTest, DefaultCommaSeparator) {
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Ranges = std::move(*ER);
EXPECT_EQ(Ranges.size(), 3U);
- EXPECT_EQ(Ranges[0].Begin, 1);
- EXPECT_EQ(Ranges[0].End, 5);
- EXPECT_EQ(Ranges[1].Begin, 10);
- EXPECT_EQ(Ranges[1].End, 10);
- EXPECT_EQ(Ranges[2].Begin, 15);
- EXPECT_EQ(Ranges[2].End, 20);
+ EXPECT_EQ(Ranges[0].getBegin(), 1);
+ EXPECT_EQ(Ranges[0].getEnd(), 5);
+ EXPECT_EQ(Ranges[1].getBegin(), 10);
+ EXPECT_EQ(Ranges[1].getEnd(), 10);
+ EXPECT_EQ(Ranges[2].getBegin(), 15);
+ EXPECT_EQ(Ranges[2].getEnd(), 20);
}
TEST(RangeTest, MergeAdjacentRanges) {
>From 22b50851508f774aadb9818b55900cbf36dc644b Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 21:21:46 +0000
Subject: [PATCH 33/49] better range size function
---
llvm/include/llvm/Support/Range.h | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 58dfc2637749d..8e3f174447dd4 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -20,6 +20,7 @@
#include "llvm/Support/Error.h"
#include <cassert>
#include <cstdint>
+#include <limits>
namespace llvm {
class raw_ostream;
@@ -62,7 +63,20 @@ class Range {
}
/// Get the size of this range.
- int64_t size() const { return End - Begin + 1; }
+ uint64_t size() const {
+ if (Begin >= 0 || End < 0) {
+ // Safe: (End - Begin) fits in int64_t in both same-sign cases.
+ return static_cast<uint64_t>(End - Begin) + 1;
+ }
+ // Mixed signs: Begin < 0 <= End.
+ // Handle potential extreme overflow case explicitly.
+ assert(!(Begin == std::numeric_limits<int64_t>::min() &&
+ End == std::numeric_limits<int64_t>::max()) &&
+ "Range size would overflow uint64_t");
+ // Compute |Begin| without overflowing when Begin == INT64_MIN.
+ const uint64_t AbsBegin = static_cast<uint64_t>(-(Begin + 1)) + 1;
+ return static_cast<uint64_t>(End) + AbsBegin + 1;
+ }
/// Print the range to the output stream.
void print(raw_ostream &OS) const {
>From 07510316229e32b09cb618089d14539af9480d12 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 21:25:19 +0000
Subject: [PATCH 34/49] range size checks
---
llvm/unittests/Support/RangeTest.cpp | 38 ++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 2127d5761c8e7..d0b22efaae2e5 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -9,6 +9,7 @@
#include "llvm/Support/Range.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
+#include <limits>
using namespace llvm;
@@ -32,6 +33,43 @@ TEST(RangeTest, SingleValueRange) {
EXPECT_FALSE(R.contains(43));
}
+TEST(RangeTest, SizeBasic) {
+ Range R1(5, 10);
+ EXPECT_EQ(R1.size(), 6u);
+
+ Range R2(0, 0);
+ EXPECT_EQ(R2.size(), 1u);
+}
+
+TEST(RangeTest, SizeMixedSigns) {
+ Range R1(-2, 2);
+ EXPECT_EQ(R1.size(), 5u);
+
+ Range R2(-1, 0);
+ EXPECT_EQ(R2.size(), 2u);
+}
+
+TEST(RangeTest, SizeExtremesNonOverflow) {
+ // [INT64_MIN, -1] has size 2^63
+ Range R1(std::numeric_limits<int64_t>::min(), -1);
+ EXPECT_EQ(R1.size(), (1ULL << 63));
+
+ // [0, INT64_MAX] has size 2^63
+ Range R2(0, std::numeric_limits<int64_t>::max());
+ EXPECT_EQ(R2.size(), (1ULL << 63));
+
+ // [INT64_MIN, 0] has size 2^63 + 1
+ Range R3(std::numeric_limits<int64_t>::min(), 0);
+ EXPECT_EQ(R3.size(), (1ULL << 63) + 1);
+
+ // Small extreme windows
+ Range R4(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::min() + 10);
+ EXPECT_EQ(R4.size(), 11u);
+
+ Range R5(std::numeric_limits<int64_t>::max() - 10, std::numeric_limits<int64_t>::max());
+ EXPECT_EQ(R5.size(), 11u);
+}
+
TEST(RangeTest, RangeOverlaps) {
Range R1(1, 5);
Range R2(3, 8);
>From 44a496df72a18ac58677d01c01ee69c4a8f3e69e Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 21:25:25 +0000
Subject: [PATCH 35/49] format
---
llvm/unittests/Support/RangeTest.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index d0b22efaae2e5..41019006e63bb 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -63,10 +63,12 @@ TEST(RangeTest, SizeExtremesNonOverflow) {
EXPECT_EQ(R3.size(), (1ULL << 63) + 1);
// Small extreme windows
- Range R4(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::min() + 10);
+ Range R4(std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::min() + 10);
EXPECT_EQ(R4.size(), 11u);
- Range R5(std::numeric_limits<int64_t>::max() - 10, std::numeric_limits<int64_t>::max());
+ Range R5(std::numeric_limits<int64_t>::max() - 10,
+ std::numeric_limits<int64_t>::max());
EXPECT_EQ(R5.size(), 11u);
}
>From a183992e755356e7968d11d924e61c810691e013 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 5 Sep 2025 21:29:48 +0000
Subject: [PATCH 36/49] format
---
llvm/lib/IR/OptBisect.cpp | 10 +++++-----
llvm/unittests/Support/RangeTest.cpp | 8 ++++----
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 0523d1450751e..9313b7879ef09 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -37,13 +37,13 @@ static cl::opt<int> OptBisectLimit(
"opt-bisect-limit", cl::Hidden, cl::init(-1), cl::Optional,
cl::cb<void, int>([](int Limit) {
if (Limit == -1)
- // -1 means run all passes
+ // -1 means run all passes.
getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
else if (Limit == 0)
- // 0 means run no passes
+ // 0 means run no passes.
getOptBisector().setRanges({{0, 0}});
else if (Limit > 0)
- // Convert limit to range 1-Limit
+ // Convert limit to range 1-Limit.
getOptBisector().setRanges({{1, Limit}});
else
llvm_unreachable(
@@ -57,7 +57,7 @@ static cl::opt<std::string> OptBisectRanges(
"opt-bisect", cl::Hidden, cl::Optional,
cl::cb<void, const std::string &>([](const std::string &RangeStr) {
if (RangeStr == "-1") {
- // -1 means run all passes
+ // -1 means run all passes.
getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
return;
}
@@ -107,7 +107,7 @@ bool OptBisect::shouldRunPass(StringRef PassName,
int CurBisectNum = ++LastBisectNum;
- // Check if current pass number falls within any of the specified ranges
+ // Check if current pass number falls within any of the specified ranges.
bool ShouldRun = RangeUtils::contains(BisectRanges, CurBisectNum);
if (OptBisectVerbose)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 41019006e63bb..172937c23f033 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -50,19 +50,19 @@ TEST(RangeTest, SizeMixedSigns) {
}
TEST(RangeTest, SizeExtremesNonOverflow) {
- // [INT64_MIN, -1] has size 2^63
+ // [INT64_MIN, -1] has size 2^63.
Range R1(std::numeric_limits<int64_t>::min(), -1);
EXPECT_EQ(R1.size(), (1ULL << 63));
- // [0, INT64_MAX] has size 2^63
+ // [0, INT64_MAX] has size 2^63.
Range R2(0, std::numeric_limits<int64_t>::max());
EXPECT_EQ(R2.size(), (1ULL << 63));
- // [INT64_MIN, 0] has size 2^63 + 1
+ // [INT64_MIN, 0] has size 2^63 + 1.
Range R3(std::numeric_limits<int64_t>::min(), 0);
EXPECT_EQ(R3.size(), (1ULL << 63) + 1);
- // Small extreme windows
+ // Small extreme windows.
Range R4(std::numeric_limits<int64_t>::min(),
std::numeric_limits<int64_t>::min() + 10);
EXPECT_EQ(R4.size(), 11u);
>From da5a434002e7750f906ca0f54ec4d7dfd326222b Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Mon, 22 Sep 2025 23:59:16 +0000
Subject: [PATCH 37/49] use list separator
---
llvm/lib/Support/Range.cpp | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/Range.cpp
index 2fe00aa0234ab..f4e72fea5f0a0 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/Range.cpp
@@ -11,7 +11,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
-#include <sstream>
+#include <string>
using namespace llvm;
@@ -78,17 +78,16 @@ bool RangeUtils::contains(ArrayRef<Range> Ranges, int64_t Value) {
void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges,
char Separator) {
- if (Ranges.empty())
+ if (Ranges.empty()) {
OS << "empty";
- else {
- bool IsFirst = true;
- for (const Range &R : Ranges) {
- if (!IsFirst)
- OS << Separator;
- else
- IsFirst = false;
- R.print(OS);
- }
+ return;
+ }
+
+ std::string Sep(1, Separator);
+ ListSeparator LS(Sep);
+ for (const Range &R : Ranges) {
+ OS << LS;
+ R.print(OS);
}
}
>From 5157263244ef13e65007507677768b5d9287032c Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 00:20:34 +0000
Subject: [PATCH 38/49] remove size
---
llvm/include/llvm/Support/Range.h | 17 ------------
llvm/unittests/Support/RangeTest.cpp | 39 ----------------------------
2 files changed, 56 deletions(-)
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/Range.h
index 8e3f174447dd4..5b039e02826e9 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/Range.h
@@ -20,7 +20,6 @@
#include "llvm/Support/Error.h"
#include <cassert>
#include <cstdint>
-#include <limits>
namespace llvm {
class raw_ostream;
@@ -62,22 +61,6 @@ class Range {
return Begin <= Other.End && End >= Other.Begin;
}
- /// Get the size of this range.
- uint64_t size() const {
- if (Begin >= 0 || End < 0) {
- // Safe: (End - Begin) fits in int64_t in both same-sign cases.
- return static_cast<uint64_t>(End - Begin) + 1;
- }
- // Mixed signs: Begin < 0 <= End.
- // Handle potential extreme overflow case explicitly.
- assert(!(Begin == std::numeric_limits<int64_t>::min() &&
- End == std::numeric_limits<int64_t>::max()) &&
- "Range size would overflow uint64_t");
- // Compute |Begin| without overflowing when Begin == INT64_MIN.
- const uint64_t AbsBegin = static_cast<uint64_t>(-(Begin + 1)) + 1;
- return static_cast<uint64_t>(End) + AbsBegin + 1;
- }
-
/// Print the range to the output stream.
void print(raw_ostream &OS) const {
if (Begin == End)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 172937c23f033..9f2ef4b81d7c9 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -33,45 +33,6 @@ TEST(RangeTest, SingleValueRange) {
EXPECT_FALSE(R.contains(43));
}
-TEST(RangeTest, SizeBasic) {
- Range R1(5, 10);
- EXPECT_EQ(R1.size(), 6u);
-
- Range R2(0, 0);
- EXPECT_EQ(R2.size(), 1u);
-}
-
-TEST(RangeTest, SizeMixedSigns) {
- Range R1(-2, 2);
- EXPECT_EQ(R1.size(), 5u);
-
- Range R2(-1, 0);
- EXPECT_EQ(R2.size(), 2u);
-}
-
-TEST(RangeTest, SizeExtremesNonOverflow) {
- // [INT64_MIN, -1] has size 2^63.
- Range R1(std::numeric_limits<int64_t>::min(), -1);
- EXPECT_EQ(R1.size(), (1ULL << 63));
-
- // [0, INT64_MAX] has size 2^63.
- Range R2(0, std::numeric_limits<int64_t>::max());
- EXPECT_EQ(R2.size(), (1ULL << 63));
-
- // [INT64_MIN, 0] has size 2^63 + 1.
- Range R3(std::numeric_limits<int64_t>::min(), 0);
- EXPECT_EQ(R3.size(), (1ULL << 63) + 1);
-
- // Small extreme windows.
- Range R4(std::numeric_limits<int64_t>::min(),
- std::numeric_limits<int64_t>::min() + 10);
- EXPECT_EQ(R4.size(), 11u);
-
- Range R5(std::numeric_limits<int64_t>::max() - 10,
- std::numeric_limits<int64_t>::max());
- EXPECT_EQ(R5.size(), 11u);
-}
-
TEST(RangeTest, RangeOverlaps) {
Range R1(1, 5);
Range R2(3, 8);
>From 1dc82a20d30c703950edd5b7e456fff8ca1480fe Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 00:21:15 +0000
Subject: [PATCH 39/49] redundant include
---
llvm/unittests/Support/RangeTest.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
index 9f2ef4b81d7c9..2127d5761c8e7 100644
--- a/llvm/unittests/Support/RangeTest.cpp
+++ b/llvm/unittests/Support/RangeTest.cpp
@@ -9,7 +9,6 @@
#include "llvm/Support/Range.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
-#include <limits>
using namespace llvm;
>From 710cdcfe702c9e24e15000722b61f35a1a9f67cb Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 20:50:58 +0000
Subject: [PATCH 40/49] IntegerInclusiveInterval
---
llvm/include/llvm/IR/OptBisect.h | 8 +-
llvm/include/llvm/Support/DebugCounter.h | 8 +-
.../{Range.h => IntegerInclusiveInterval.h} | 76 +++---
llvm/lib/IR/OptBisect.cpp | 6 +-
llvm/lib/Support/CMakeLists.txt | 2 +-
llvm/lib/Support/DebugCounter.cpp | 7 +-
...Range.cpp => IntegerInclusiveInterval.cpp} | 67 ++---
.../reduce-chunk-list/reduce-chunk-list.cpp | 26 +-
llvm/unittests/Support/CMakeLists.txt | 2 +-
.../Support/IntegerInclusiveIntervalTest.cpp | 244 ++++++++++++++++++
llvm/unittests/Support/RangeTest.cpp | 244 ------------------
11 files changed, 349 insertions(+), 341 deletions(-)
rename llvm/include/llvm/Support/{Range.h => IntegerInclusiveInterval.h} (51%)
rename llvm/lib/Support/{Range.cpp => IntegerInclusiveInterval.cpp} (58%)
create mode 100644 llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
delete mode 100644 llvm/unittests/Support/RangeTest.cpp
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index e051b7960cd49..033107ab16468 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -19,7 +19,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Range.h"
+#include "llvm/Support/IntegerInclusiveInterval.h"
namespace llvm {
@@ -71,8 +71,8 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// isEnabled() should return true before calling shouldRunPass().
bool isEnabled() const override { return !BisectRanges.empty(); }
- /// Set ranges directly from a RangeList.
- void setRanges(RangeUtils::RangeList Ranges) {
+ /// Set intervals directly from an IntervalList.
+ void setRanges(IntegerIntervalUtils::IntervalList Ranges) {
BisectRanges = std::move(Ranges);
}
@@ -84,7 +84,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
private:
mutable int LastBisectNum = 0;
- RangeUtils::RangeList BisectRanges;
+ IntegerIntervalUtils::IntervalList BisectRanges;
};
/// This class implements a mechanism to disable passes and individual
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index cf708b0cbc4dc..2115995f6b190 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -48,7 +48,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Range.h"
+#include "llvm/Support/IntegerInclusiveInterval.h"
#include <string>
namespace llvm {
@@ -72,7 +72,7 @@ class DebugCounter {
uint64_t CurrChunkIdx = 0;
StringRef Name;
StringRef Desc;
- RangeUtils::RangeList Chunks;
+ IntegerIntervalUtils::IntervalList Chunks;
public:
CounterInfo(StringRef Name, StringRef Desc) : Name(Name), Desc(Desc) {
@@ -80,11 +80,11 @@ class DebugCounter {
}
};
- LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<Range> Ranges);
+ LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Ranges);
/// Return true on parsing error and print the error message on the
/// llvm::errs()
- LLVM_ABI static bool parseChunks(StringRef Str, RangeUtils::RangeList &Res);
+ LLVM_ABI static bool parseChunks(StringRef Str, IntegerIntervalUtils::IntervalList &Res);
/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
diff --git a/llvm/include/llvm/Support/Range.h b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
similarity index 51%
rename from llvm/include/llvm/Support/Range.h
rename to llvm/include/llvm/Support/IntegerInclusiveInterval.h
index 5b039e02826e9..43d8ac2869e12 100644
--- a/llvm/include/llvm/Support/Range.h
+++ b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
@@ -27,19 +27,19 @@ class raw_ostream;
namespace llvm {
-/// Represents a range of integers [Begin, End], inclusive on both ends, where
-/// Begin <= End.
-class Range {
+/// Represents an inclusive integer interval [Begin, End] where Begin <= End.
+class IntegerInclusiveInterval {
int64_t Begin;
int64_t End;
public:
- /// Create a range [Begin, End].
- Range(int64_t Begin, int64_t End) : Begin(Begin), End(End) {
+ /// Create an interval [Begin, End].
+ IntegerInclusiveInterval(int64_t Begin, int64_t End)
+ : Begin(Begin), End(End) {
assert(Begin <= End && "Range Begin must be <= End");
}
- /// Create a range [Single, Single].
- Range(int64_t Single) : Begin(Single), End(Single) {}
+ /// Create a singleton interval [Single, Single].
+ IntegerInclusiveInterval(int64_t Single) : Begin(Single), End(Single) {}
int64_t getBegin() const { return Begin; }
int64_t getEnd() const { return End; }
@@ -57,7 +57,7 @@ class Range {
bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
/// Check if this range overlaps with another range.
- bool overlaps(const Range &Other) const {
+ bool overlaps(const IntegerInclusiveInterval &Other) const {
return Begin <= Other.End && End >= Other.Begin;
}
@@ -69,40 +69,40 @@ class Range {
OS << Begin << "-" << End;
}
- bool operator==(const Range &Other) const {
+ bool operator==(const IntegerInclusiveInterval &Other) const {
return Begin == Other.Begin && End == Other.End;
}
};
-/// Utility class for parsing and managing range specifications.
-class RangeUtils {
-public:
- using RangeList = SmallVector<Range, 8>;
-
- /// Parse a range specification string like "1-10,20-30,45" or
- /// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping.
- /// \param RangeStr The string to parse.
- /// \param Separator The separator character to use (',' or ':').
- /// \returns Expected<RangeList> containing the parsed ranges on success,
- /// or an Error on failure.
- static Expected<RangeList> parseRanges(StringRef RangeStr,
- char Separator = ',');
-
- /// Check if a value is contained in any of the ranges.
- static bool contains(ArrayRef<Range> Ranges, int64_t Value);
-
- /// Print ranges to output stream.
- /// \param OS The output stream to print to.
- /// \param Ranges The ranges to print.
- /// \param Separator The separator character to use between ranges (i.e. ','
- /// or ':').
- static void printRanges(raw_ostream &OS, ArrayRef<Range> Ranges,
- char Separator = ',');
-
- /// Merge adjacent/consecutive ranges into single ranges.
- /// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
- static RangeList mergeAdjacentRanges(ArrayRef<Range> Ranges);
-};
+namespace IntegerIntervalUtils {
+
+/// A list of integer ranges.
+using IntervalList = SmallVector<IntegerInclusiveInterval, 8>;
+
+/// Parse a range specification string like "1-10,20-30,45" or
+/// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping.
+/// \param RangeStr The string to parse.
+/// \param Separator The separator character to use (',' or ':').
+/// \returns Expected<RangeList> containing the parsed ranges on success,
+/// or an Error on failure.
+Expected<IntervalList> parseIntervals(StringRef RangeStr,
+ char Separator = ',');
+
+/// Check if a value is contained in any of the ranges.
+bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);
+
+/// Print ranges to output stream.
+/// \param OS The output stream to print to.
+/// \param Ranges The ranges to print.
+/// \param Separator The separator character to use between ranges (i.e. ',' or ':').
+void printIntervals(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals,
+ char Separator = ',');
+
+/// Merge adjacent/consecutive ranges into single ranges.
+/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
+IntervalList mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);
+
+} // end namespace IntegerIntervalUtils
} // end namespace llvm
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 9313b7879ef09..decdf971735ff 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -16,7 +16,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Range.h"
+#include "llvm/Support/IntegerInclusiveInterval.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdlib>
@@ -62,7 +62,7 @@ static cl::opt<std::string> OptBisectRanges(
return;
}
- auto Ranges = RangeUtils::parseRanges(RangeStr);
+ auto Ranges = IntegerIntervalUtils::parseIntervals(RangeStr);
if (!Ranges) {
handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
errs() << "Error: Invalid range specification for -opt-bisect: "
@@ -108,7 +108,7 @@ bool OptBisect::shouldRunPass(StringRef PassName,
int CurBisectNum = ++LastBisectNum;
// Check if current pass number falls within any of the specified ranges.
- bool ShouldRun = RangeUtils::contains(BisectRanges, CurBisectNum);
+ bool ShouldRun = IntegerIntervalUtils::contains(BisectRanges, CurBisectNum);
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 14776ed1f7430..099b0e55579be 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -236,7 +236,7 @@ add_llvm_component_library(LLVMSupport
PluginLoader.cpp
PrettyStackTrace.cpp
RandomNumberGenerator.cpp
- Range.cpp
+ IntegerInclusiveInterval.cpp
Regex.cpp
RewriteBuffer.cpp
RewriteRope.cpp
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index ed011b5d2d271..ef0fd545db3af 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -10,8 +10,9 @@ using namespace llvm;
namespace llvm {
-void DebugCounter::printChunks(raw_ostream &OS, ArrayRef<Range> Ranges) {
- RangeUtils::printRanges(OS, Ranges, ':');
+void DebugCounter::printChunks(raw_ostream &OS,
+ ArrayRef<IntegerInclusiveInterval> Ranges) {
+ IntegerIntervalUtils::printIntervals(OS, Ranges, ':');
}
} // namespace llvm
@@ -132,7 +133,7 @@ void DebugCounter::push_back(const std::string &Val) {
return;
}
- auto ExpectedChunks = RangeUtils::parseRanges(CounterPair.second, ':');
+ auto ExpectedChunks = IntegerIntervalUtils::parseIntervals(CounterPair.second, ':');
if (!ExpectedChunks) {
handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
errs() << "DebugCounter Error: " << E.getMessage() << "\n";
diff --git a/llvm/lib/Support/Range.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
similarity index 58%
rename from llvm/lib/Support/Range.cpp
rename to llvm/lib/Support/IntegerInclusiveInterval.cpp
index f4e72fea5f0a0..c44b8b7f05446 100644
--- a/llvm/lib/Support/Range.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/Range.h"
+#include "llvm/Support/IntegerInclusiveInterval.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Regex.h"
@@ -15,14 +15,16 @@
using namespace llvm;
-Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
- char Separator) {
- RangeList Ranges;
+namespace llvm {
+namespace IntegerIntervalUtils {
+
+Expected<IntervalList> parseIntervals(StringRef Str, char Separator) {
+ IntervalList Intervals;
if (Str.empty())
- return std::move(Ranges);
+ return std::move(Intervals);
- // Regex to match either single number or range "num1-num2".
+ // Regex to match either single number or interval "num1-num2".
const Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
for (StringRef Part : llvm::split(Str, Separator)) {
@@ -55,62 +57,65 @@ Expected<RangeUtils::RangeList> RangeUtils::parseRanges(StringRef Str,
// Single number.
End = Begin;
- // Check ordering constraint (ranges must be in increasing order).
- if (!Ranges.empty() && Begin <= Ranges.back().getEnd())
+ // Check ordering constraint (intervals must be in increasing order).
+ if (!Intervals.empty() && Begin <= Intervals.back().getEnd())
return createStringError(
std::errc::invalid_argument,
- "Expected ranges to be in increasing order: %lld <= %lld", Begin,
- Ranges.back().getEnd());
+ "Expected intervals to be in increasing order: %lld <= %lld", Begin,
+ Intervals.back().getEnd());
- Ranges.push_back(Range(Begin, End));
+ Intervals.push_back(IntegerInclusiveInterval(Begin, End));
}
- return Ranges;
+ return Intervals;
}
-bool RangeUtils::contains(ArrayRef<Range> Ranges, int64_t Value) {
- for (const Range &R : Ranges) {
- if (R.contains(Value))
+bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value) {
+ for (const IntegerInclusiveInterval &It : Intervals) {
+ if (It.contains(Value))
return true;
}
return false;
}
-void RangeUtils::printRanges(raw_ostream &OS, ArrayRef<Range> Ranges,
- char Separator) {
- if (Ranges.empty()) {
+void printIntervals(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals,
+ char Separator) {
+ if (Intervals.empty()) {
OS << "empty";
return;
}
std::string Sep(1, Separator);
ListSeparator LS(Sep);
- for (const Range &R : Ranges) {
+ for (const IntegerInclusiveInterval &It : Intervals) {
OS << LS;
- R.print(OS);
+ It.print(OS);
}
}
-RangeUtils::RangeList RangeUtils::mergeAdjacentRanges(ArrayRef<Range> Ranges) {
- if (Ranges.empty())
+IntervalList mergeAdjacentIntervals(
+ ArrayRef<IntegerInclusiveInterval> Intervals) {
+ if (Intervals.empty())
return {};
- RangeList Result;
- Result.push_back(Ranges[0]);
-
- for (size_t I = 1; I < Ranges.size(); ++I) {
- const Range &Current = Ranges[I];
- Range &Last = Result.back();
+ IntervalList Result;
+ Result.push_back(Intervals[0]);
- // Check if current range is adjacent to the last merged range.
+ for (const IntegerInclusiveInterval &Current : Intervals.drop_front()) {
+ IntegerInclusiveInterval &Last = Result.back();
+ // Check if current interval is adjacent to the last merged interval.
if (Current.getBegin() == Last.getEnd() + 1) {
- // Merge by extending the end of the last range.
+ // Merge by extending the end of the last interval.
Last.setEnd(Current.getEnd());
} else {
- // Not adjacent, add as separate range.
+ // Not adjacent, add as separate interval.
Result.push_back(Current);
}
}
return Result;
}
+
+} // end namespace IntegerIntervalUtils
+
+} // end namespace llvm
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index de41ca520c408..2de15889225a4 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -13,7 +13,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Program.h"
-#include "llvm/Support/Range.h"
+#include "llvm/Support/IntegerInclusiveInterval.h"
using namespace llvm;
@@ -25,13 +25,14 @@ static cl::opt<bool> Pessimist("pessimist", cl::init(false));
namespace {
-bool isStillInteresting(ArrayRef<Range> Chunks) {
- RangeUtils::RangeList SimpleChunks = RangeUtils::mergeAdjacentRanges(Chunks);
+bool isStillInteresting(ArrayRef<IntegerInclusiveInterval> Chunks) {
+ IntegerIntervalUtils::IntervalList SimpleChunks =
+ IntegerIntervalUtils::mergeAdjacentIntervals(Chunks);
std::string ChunkStr;
{
raw_string_ostream OS(ChunkStr);
- RangeUtils::printRanges(OS, SimpleChunks);
+ IntegerIntervalUtils::printIntervals(OS, SimpleChunks);
}
errs() << "Checking with: " << ChunkStr << "\n";
@@ -58,9 +59,9 @@ bool isStillInteresting(ArrayRef<Range> Chunks) {
return Res;
}
-bool increaseGranularity(RangeUtils::RangeList &Chunks) {
+bool increaseGranularity(IntegerIntervalUtils::IntervalList &Chunks) {
errs() << "Increasing granularity\n";
- RangeUtils::RangeList NewChunks;
+ IntegerIntervalUtils::IntervalList NewChunks;
bool SplitOne = false;
for (auto &C : Chunks) {
@@ -68,8 +69,8 @@ bool increaseGranularity(RangeUtils::RangeList &Chunks) {
NewChunks.push_back(C);
} else {
int64_t Half = (C.getBegin() + C.getEnd()) / 2;
- NewChunks.push_back(Range(C.getBegin(), Half));
- NewChunks.push_back(Range(Half + 1, C.getEnd()));
+ NewChunks.push_back(IntegerInclusiveInterval(C.getBegin(), Half));
+ NewChunks.push_back(IntegerInclusiveInterval(Half + 1, C.getEnd()));
SplitOne = true;
}
}
@@ -84,14 +85,14 @@ bool increaseGranularity(RangeUtils::RangeList &Chunks) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
- auto ExpectedChunks = RangeUtils::parseRanges(StartChunks, ',');
+ auto ExpectedChunks = IntegerIntervalUtils::parseIntervals(StartChunks, ',');
if (!ExpectedChunks) {
handleAllErrors(ExpectedChunks.takeError(), [](const StringError &E) {
errs() << "Error parsing chunks: " << E.getMessage() << "\n";
});
return 1;
}
- RangeUtils::RangeList CurrChunks = std::move(*ExpectedChunks);
+ IntegerIntervalUtils::IntervalList CurrChunks = std::move(*ExpectedChunks);
auto Program = sys::findProgramByName(ReproductionCmd);
if (!Program) {
@@ -131,7 +132,8 @@ int main(int argc, char **argv) {
}
errs() << "Minimal Chunks = ";
- RangeUtils::printRanges(llvm::errs(),
- RangeUtils::mergeAdjacentRanges(CurrChunks));
+ IntegerIntervalUtils::printIntervals(
+ llvm::errs(),
+ IntegerIntervalUtils::mergeAdjacentIntervals(CurrChunks));
errs() << "\n";
}
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index db60a9ea5e9f0..a8bf96bbe096f 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -76,7 +76,7 @@ add_llvm_unittest(SupportTests
ProcessTest.cpp
ProgramTest.cpp
ProgramStackTest.cpp
- RangeTest.cpp
+ IntegerInclusiveIntervalTest.cpp
RecyclerTest.cpp
RegexTest.cpp
ReverseIterationTest.cpp
diff --git a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
new file mode 100644
index 0000000000000..b57c779378736
--- /dev/null
+++ b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
@@ -0,0 +1,244 @@
+//===- llvm/unittests/Support/RangeTest.cpp - Range tests ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/IntegerInclusiveInterval.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(IntegerInclusiveIntervalTest, BasicInterval) {
+ IntegerInclusiveInterval R(5, 10);
+ EXPECT_EQ(R.getBegin(), 5);
+ EXPECT_EQ(R.getEnd(), 10);
+ EXPECT_TRUE(R.contains(5));
+ EXPECT_TRUE(R.contains(7));
+ EXPECT_TRUE(R.contains(10));
+ EXPECT_FALSE(R.contains(4));
+ EXPECT_FALSE(R.contains(11));
+}
+
+TEST(IntegerInclusiveIntervalTest, SingleValueInterval) {
+ IntegerInclusiveInterval R(42);
+ EXPECT_EQ(R.getBegin(), 42);
+ EXPECT_EQ(R.getEnd(), 42);
+ EXPECT_TRUE(R.contains(42));
+ EXPECT_FALSE(R.contains(41));
+ EXPECT_FALSE(R.contains(43));
+}
+
+TEST(IntegerInclusiveIntervalTest, IntervalOverlaps) {
+ IntegerInclusiveInterval R1(1, 5);
+ IntegerInclusiveInterval R2(3, 8);
+ IntegerInclusiveInterval R3(6, 10);
+ IntegerInclusiveInterval R4(11, 15);
+
+ EXPECT_TRUE(R1.overlaps(R2));
+ EXPECT_TRUE(R2.overlaps(R1));
+ EXPECT_TRUE(R2.overlaps(R3));
+ EXPECT_FALSE(R1.overlaps(R3));
+ EXPECT_FALSE(R1.overlaps(R4));
+ EXPECT_FALSE(R3.overlaps(R4));
+}
+
+TEST(IntegerIntervalUtilsTest, ParseSingleNumber) {
+ auto ER = IntegerIntervalUtils::parseIntervals("42");
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+ EXPECT_EQ(Ranges.size(), 1U);
+ EXPECT_EQ(Ranges[0].getBegin(), 42);
+ EXPECT_EQ(Ranges[0].getEnd(), 42);
+}
+
+TEST(IntegerIntervalUtilsTest, ParseSingleInterval) {
+ auto ER = IntegerIntervalUtils::parseIntervals("10-20");
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+ EXPECT_EQ(Ranges.size(), 1U);
+ EXPECT_EQ(Ranges[0].getBegin(), 10);
+ EXPECT_EQ(Ranges[0].getEnd(), 20);
+}
+
+TEST(IntegerIntervalUtilsTest, ParseMultipleIntervals) {
+ auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+ EXPECT_EQ(Ranges.size(), 3U);
+
+ // Ranges are in input order (DebugCounter style).
+ EXPECT_EQ(Ranges[0].getBegin(), 1);
+ EXPECT_EQ(Ranges[0].getEnd(), 5);
+ EXPECT_EQ(Ranges[1].getBegin(), 10);
+ EXPECT_EQ(Ranges[1].getEnd(), 10);
+ EXPECT_EQ(Ranges[2].getBegin(), 15);
+ EXPECT_EQ(Ranges[2].getEnd(), 20);
+}
+
+TEST(IntegerIntervalUtilsTest, ParseColonSeparatedIntervals) {
+ auto ER = IntegerIntervalUtils::parseIntervals("1-5:10:15-20", ':');
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+ EXPECT_EQ(Ranges.size(), 3U);
+ EXPECT_EQ(Ranges[0].getBegin(), 1);
+ EXPECT_EQ(Ranges[0].getEnd(), 5);
+ EXPECT_EQ(Ranges[1].getBegin(), 10);
+ EXPECT_EQ(Ranges[1].getEnd(), 10);
+ EXPECT_EQ(Ranges[2].getBegin(), 15);
+ EXPECT_EQ(Ranges[2].getEnd(), 20);
+}
+
+TEST(IntegerIntervalUtilsTest, ParseEmptyString) {
+ auto ER = IntegerIntervalUtils::parseIntervals("");
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+ EXPECT_TRUE(Ranges.empty());
+}
+
+TEST(IntegerIntervalUtilsTest, ParseInvalidIntervals) {
+ // Invalid number.
+ auto ER1 = IntegerIntervalUtils::parseIntervals("abc");
+ EXPECT_THAT_EXPECTED(ER1, Failed());
+ consumeError(ER1.takeError());
+
+ // Invalid range (begin > end).
+ auto ER2 = IntegerIntervalUtils::parseIntervals("10-5");
+ EXPECT_THAT_EXPECTED(ER2, Failed());
+ consumeError(ER2.takeError());
+
+ // Out of order ranges (DebugCounter constraint and overlap).
+ auto ER3 = IntegerIntervalUtils::parseIntervals("10,5");
+ EXPECT_THAT_EXPECTED(ER3, Failed());
+ consumeError(ER3.takeError());
+
+ auto ER4 = IntegerIntervalUtils::parseIntervals("1-5,3-7");
+ EXPECT_THAT_EXPECTED(ER4, Failed());
+ consumeError(ER4.takeError());
+}
+
+TEST(IntegerIntervalUtilsTest, Contains) {
+ auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 1));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 3));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 5));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 10));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 15));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 18));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 20));
+
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 6));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 9));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 11));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 14));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 21));
+}
+
+TEST(IntegerIntervalUtilsTest, SeparatorParameter) {
+ IntegerIntervalUtils::IntervalList ColonRanges, CommaRanges;
+
+ // Test explicit separator parameters.
+ auto ERC = IntegerIntervalUtils::parseIntervals("1-5:10:15-20", ':');
+ ASSERT_THAT_EXPECTED(ERC, Succeeded());
+ ColonRanges = std::move(*ERC);
+
+ auto ERM = IntegerIntervalUtils::parseIntervals("1-5,10,15-20", ',');
+ ASSERT_THAT_EXPECTED(ERM, Succeeded());
+ CommaRanges = std::move(*ERM);
+
+ EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
+ for (size_t I = 0; I < ColonRanges.size(); ++I) {
+ EXPECT_EQ(ColonRanges[I].getBegin(), CommaRanges[I].getBegin());
+ EXPECT_EQ(ColonRanges[I].getEnd(), CommaRanges[I].getEnd());
+ }
+
+ // Test that both work with contains().
+ EXPECT_TRUE(IntegerIntervalUtils::contains(ColonRanges, 3));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(CommaRanges, 3));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(ColonRanges, 10));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(CommaRanges, 10));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(ColonRanges, 18));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(CommaRanges, 18));
+
+ EXPECT_FALSE(IntegerIntervalUtils::contains(ColonRanges, 8));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(CommaRanges, 8));
+}
+
+TEST(IntegerIntervalUtilsTest, DefaultCommaSeparator) {
+ // Test that comma is the default separator.
+ auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
+ ASSERT_THAT_EXPECTED(ER, Succeeded());
+ auto Ranges = std::move(*ER);
+ EXPECT_EQ(Ranges.size(), 3U);
+ EXPECT_EQ(Ranges[0].getBegin(), 1);
+ EXPECT_EQ(Ranges[0].getEnd(), 5);
+ EXPECT_EQ(Ranges[1].getBegin(), 10);
+ EXPECT_EQ(Ranges[1].getEnd(), 10);
+ EXPECT_EQ(Ranges[2].getBegin(), 15);
+ EXPECT_EQ(Ranges[2].getEnd(), 20);
+}
+
+TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
+ IntegerIntervalUtils::IntervalList Input, Expected, Result;
+
+ // Empty input
+ Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ EXPECT_TRUE(Result.empty());
+
+ // Single range - no change.
+ Input.push_back(IntegerInclusiveInterval(5, 10));
+ Expected.push_back(IntegerInclusiveInterval(5, 10));
+ Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Adjacent ranges should merge.
+ Input.clear();
+ Expected.clear();
+ Input.push_back(IntegerInclusiveInterval(1, 3));
+ Input.push_back(IntegerInclusiveInterval(4, 6));
+ Input.push_back(IntegerInclusiveInterval(7, 9));
+ Expected.push_back(IntegerInclusiveInterval(1, 9));
+ Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Non-adjacent ranges should not merge.
+ Input.clear();
+ Expected.clear();
+ Input.push_back(IntegerInclusiveInterval(1, 3));
+ Input.push_back(IntegerInclusiveInterval(5, 7)); // Gap between 3 and 5.
+ Input.push_back(IntegerInclusiveInterval(10, 12)); // Gap between 7 and 10.
+ Expected.push_back(IntegerInclusiveInterval(1, 3));
+ Expected.push_back(IntegerInclusiveInterval(5, 7));
+ Expected.push_back(IntegerInclusiveInterval(10, 12));
+ Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Mixed adjacent and non-adjacent.
+ Input.clear();
+ Expected.clear();
+ Input.push_back(IntegerInclusiveInterval(1, 3));
+ Input.push_back(IntegerInclusiveInterval(4, 6)); // Adjacent to first.
+ Input.push_back(IntegerInclusiveInterval(8, 10)); // Gap.
+ Input.push_back(IntegerInclusiveInterval(11, 13)); // Adjacent to third.
+ Input.push_back(IntegerInclusiveInterval(14, 16)); // Adjacent to fourth.
+ Expected.push_back(IntegerInclusiveInterval(1, 6)); // Merged 1-3 and 4-6.
+ Expected.push_back(IntegerInclusiveInterval(8, 16)); // Merged 8-10, 11-13, 14-16.
+ Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ EXPECT_EQ(Expected, Result);
+
+ // Single numbers that are adjacent.
+ Input.clear();
+ Expected.clear();
+ Input.push_back(IntegerInclusiveInterval(5));
+ Input.push_back(IntegerInclusiveInterval(6));
+ Input.push_back(IntegerInclusiveInterval(7));
+ Expected.push_back(IntegerInclusiveInterval(5, 7));
+ Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ EXPECT_EQ(Expected, Result);
+}
diff --git a/llvm/unittests/Support/RangeTest.cpp b/llvm/unittests/Support/RangeTest.cpp
deleted file mode 100644
index 2127d5761c8e7..0000000000000
--- a/llvm/unittests/Support/RangeTest.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-//===- llvm/unittests/Support/RangeTest.cpp - Range tests ----------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/Range.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-
-TEST(RangeTest, BasicRange) {
- Range R(5, 10);
- EXPECT_EQ(R.getBegin(), 5);
- EXPECT_EQ(R.getEnd(), 10);
- EXPECT_TRUE(R.contains(5));
- EXPECT_TRUE(R.contains(7));
- EXPECT_TRUE(R.contains(10));
- EXPECT_FALSE(R.contains(4));
- EXPECT_FALSE(R.contains(11));
-}
-
-TEST(RangeTest, SingleValueRange) {
- Range R(42);
- EXPECT_EQ(R.getBegin(), 42);
- EXPECT_EQ(R.getEnd(), 42);
- EXPECT_TRUE(R.contains(42));
- EXPECT_FALSE(R.contains(41));
- EXPECT_FALSE(R.contains(43));
-}
-
-TEST(RangeTest, RangeOverlaps) {
- Range R1(1, 5);
- Range R2(3, 8);
- Range R3(6, 10);
- Range R4(11, 15);
-
- EXPECT_TRUE(R1.overlaps(R2));
- EXPECT_TRUE(R2.overlaps(R1));
- EXPECT_TRUE(R2.overlaps(R3));
- EXPECT_FALSE(R1.overlaps(R3));
- EXPECT_FALSE(R1.overlaps(R4));
- EXPECT_FALSE(R3.overlaps(R4));
-}
-
-TEST(RangeUtilsTest, ParseSingleNumber) {
- auto ER = RangeUtils::parseRanges("42");
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 1U);
- EXPECT_EQ(Ranges[0].getBegin(), 42);
- EXPECT_EQ(Ranges[0].getEnd(), 42);
-}
-
-TEST(RangeUtilsTest, ParseSingleRange) {
- auto ER = RangeUtils::parseRanges("10-20");
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 1U);
- EXPECT_EQ(Ranges[0].getBegin(), 10);
- EXPECT_EQ(Ranges[0].getEnd(), 20);
-}
-
-TEST(RangeUtilsTest, ParseMultipleRanges) {
- auto ER = RangeUtils::parseRanges("1-5,10,15-20");
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 3U);
-
- // Ranges are in input order (DebugCounter style).
- EXPECT_EQ(Ranges[0].getBegin(), 1);
- EXPECT_EQ(Ranges[0].getEnd(), 5);
- EXPECT_EQ(Ranges[1].getBegin(), 10);
- EXPECT_EQ(Ranges[1].getEnd(), 10);
- EXPECT_EQ(Ranges[2].getBegin(), 15);
- EXPECT_EQ(Ranges[2].getEnd(), 20);
-}
-
-TEST(RangeUtilsTest, ParseColonSeparated) {
- auto ER = RangeUtils::parseRanges("1-5:10:15-20", ':');
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 3U);
- EXPECT_EQ(Ranges[0].getBegin(), 1);
- EXPECT_EQ(Ranges[0].getEnd(), 5);
- EXPECT_EQ(Ranges[1].getBegin(), 10);
- EXPECT_EQ(Ranges[1].getEnd(), 10);
- EXPECT_EQ(Ranges[2].getBegin(), 15);
- EXPECT_EQ(Ranges[2].getEnd(), 20);
-}
-
-TEST(RangeUtilsTest, ParseEmptyString) {
- auto ER = RangeUtils::parseRanges("");
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_TRUE(Ranges.empty());
-}
-
-TEST(RangeUtilsTest, ParseInvalidRanges) {
- // Invalid number.
- auto ER1 = RangeUtils::parseRanges("abc");
- EXPECT_THAT_EXPECTED(ER1, Failed());
- consumeError(ER1.takeError());
-
- // Invalid range (begin > end).
- auto ER2 = RangeUtils::parseRanges("10-5");
- EXPECT_THAT_EXPECTED(ER2, Failed());
- consumeError(ER2.takeError());
-
- // Out of order ranges (DebugCounter constraint and overlap).
- auto ER3 = RangeUtils::parseRanges("10,5");
- EXPECT_THAT_EXPECTED(ER3, Failed());
- consumeError(ER3.takeError());
-
- auto ER4 = RangeUtils::parseRanges("1-5,3-7");
- EXPECT_THAT_EXPECTED(ER4, Failed());
- consumeError(ER4.takeError());
-}
-
-TEST(RangeUtilsTest, Contains) {
- auto ER = RangeUtils::parseRanges("1-5,10,15-20");
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
-
- EXPECT_TRUE(RangeUtils::contains(Ranges, 1));
- EXPECT_TRUE(RangeUtils::contains(Ranges, 3));
- EXPECT_TRUE(RangeUtils::contains(Ranges, 5));
- EXPECT_TRUE(RangeUtils::contains(Ranges, 10));
- EXPECT_TRUE(RangeUtils::contains(Ranges, 15));
- EXPECT_TRUE(RangeUtils::contains(Ranges, 18));
- EXPECT_TRUE(RangeUtils::contains(Ranges, 20));
-
- EXPECT_FALSE(RangeUtils::contains(Ranges, 6));
- EXPECT_FALSE(RangeUtils::contains(Ranges, 9));
- EXPECT_FALSE(RangeUtils::contains(Ranges, 11));
- EXPECT_FALSE(RangeUtils::contains(Ranges, 14));
- EXPECT_FALSE(RangeUtils::contains(Ranges, 21));
-}
-
-TEST(RangeUtilsTest, SeparatorParameter) {
- RangeUtils::RangeList ColonRanges, CommaRanges;
-
- // Test explicit separator parameters.
- auto ERC = RangeUtils::parseRanges("1-5:10:15-20", ':');
- ASSERT_THAT_EXPECTED(ERC, Succeeded());
- ColonRanges = std::move(*ERC);
-
- auto ERM = RangeUtils::parseRanges("1-5,10,15-20", ',');
- ASSERT_THAT_EXPECTED(ERM, Succeeded());
- CommaRanges = std::move(*ERM);
-
- EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
- for (size_t I = 0; I < ColonRanges.size(); ++I) {
- EXPECT_EQ(ColonRanges[I].getBegin(), CommaRanges[I].getBegin());
- EXPECT_EQ(ColonRanges[I].getEnd(), CommaRanges[I].getEnd());
- }
-
- // Test that both work with contains().
- EXPECT_TRUE(RangeUtils::contains(ColonRanges, 3));
- EXPECT_TRUE(RangeUtils::contains(CommaRanges, 3));
- EXPECT_TRUE(RangeUtils::contains(ColonRanges, 10));
- EXPECT_TRUE(RangeUtils::contains(CommaRanges, 10));
- EXPECT_TRUE(RangeUtils::contains(ColonRanges, 18));
- EXPECT_TRUE(RangeUtils::contains(CommaRanges, 18));
-
- EXPECT_FALSE(RangeUtils::contains(ColonRanges, 8));
- EXPECT_FALSE(RangeUtils::contains(CommaRanges, 8));
-}
-
-TEST(RangeUtilsTest, DefaultCommaSeparator) {
- // Test that comma is the default separator.
- auto ER = RangeUtils::parseRanges("1-5,10,15-20");
- ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 3U);
- EXPECT_EQ(Ranges[0].getBegin(), 1);
- EXPECT_EQ(Ranges[0].getEnd(), 5);
- EXPECT_EQ(Ranges[1].getBegin(), 10);
- EXPECT_EQ(Ranges[1].getEnd(), 10);
- EXPECT_EQ(Ranges[2].getBegin(), 15);
- EXPECT_EQ(Ranges[2].getEnd(), 20);
-}
-
-TEST(RangeTest, MergeAdjacentRanges) {
- RangeUtils::RangeList Input, Expected, Result;
-
- // Empty input
- Result = RangeUtils::mergeAdjacentRanges(Input);
- EXPECT_TRUE(Result.empty());
-
- // Single range - no change.
- Input.push_back(Range(5, 10));
- Expected.push_back(Range(5, 10));
- Result = RangeUtils::mergeAdjacentRanges(Input);
- EXPECT_EQ(Expected, Result);
-
- // Adjacent ranges should merge.
- Input.clear();
- Expected.clear();
- Input.push_back(Range(1, 3));
- Input.push_back(Range(4, 6));
- Input.push_back(Range(7, 9));
- Expected.push_back(Range(1, 9));
- Result = RangeUtils::mergeAdjacentRanges(Input);
- EXPECT_EQ(Expected, Result);
-
- // Non-adjacent ranges should not merge.
- Input.clear();
- Expected.clear();
- Input.push_back(Range(1, 3));
- Input.push_back(Range(5, 7)); // Gap between 3 and 5.
- Input.push_back(Range(10, 12)); // Gap between 7 and 10.
- Expected.push_back(Range(1, 3));
- Expected.push_back(Range(5, 7));
- Expected.push_back(Range(10, 12));
- Result = RangeUtils::mergeAdjacentRanges(Input);
- EXPECT_EQ(Expected, Result);
-
- // Mixed adjacent and non-adjacent.
- Input.clear();
- Expected.clear();
- Input.push_back(Range(1, 3));
- Input.push_back(Range(4, 6)); // Adjacent to first.
- Input.push_back(Range(8, 10)); // Gap.
- Input.push_back(Range(11, 13)); // Adjacent to third.
- Input.push_back(Range(14, 16)); // Adjacent to fourth.
- Expected.push_back(Range(1, 6)); // Merged 1-3 and 4-6.
- Expected.push_back(Range(8, 16)); // Merged 8-10, 11-13, 14-16.
- Result = RangeUtils::mergeAdjacentRanges(Input);
- EXPECT_EQ(Expected, Result);
-
- // Single numbers that are adjacent.
- Input.clear();
- Expected.clear();
- Input.push_back(Range(5));
- Input.push_back(Range(6));
- Input.push_back(Range(7));
- Expected.push_back(Range(5, 7));
- Result = RangeUtils::mergeAdjacentRanges(Input);
- EXPECT_EQ(Expected, Result);
-}
>From f582b676409831060bc103a887eddd61d2699534 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 20:54:10 +0000
Subject: [PATCH 41/49] format
---
.../include/llvm/Support/IntegerInclusiveInterval.h | 12 +++++++-----
llvm/lib/Support/IntegerInclusiveInterval.cpp | 7 ++++---
llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp | 5 ++---
.../Support/IntegerInclusiveIntervalTest.cpp | 13 +++++++------
4 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/Support/IntegerInclusiveInterval.h b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
index 43d8ac2869e12..592ad127cf7bd 100644
--- a/llvm/include/llvm/Support/IntegerInclusiveInterval.h
+++ b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
@@ -85,8 +85,7 @@ using IntervalList = SmallVector<IntegerInclusiveInterval, 8>;
/// \param Separator The separator character to use (',' or ':').
/// \returns Expected<RangeList> containing the parsed ranges on success,
/// or an Error on failure.
-Expected<IntervalList> parseIntervals(StringRef RangeStr,
- char Separator = ',');
+Expected<IntervalList> parseIntervals(StringRef RangeStr, char Separator = ',');
/// Check if a value is contained in any of the ranges.
bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);
@@ -94,13 +93,16 @@ bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);
/// Print ranges to output stream.
/// \param OS The output stream to print to.
/// \param Ranges The ranges to print.
-/// \param Separator The separator character to use between ranges (i.e. ',' or ':').
-void printIntervals(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals,
+/// \param Separator The separator character to use between ranges (i.e. ',' or
+/// ':').
+void printIntervals(raw_ostream &OS,
+ ArrayRef<IntegerInclusiveInterval> Intervals,
char Separator = ',');
/// Merge adjacent/consecutive ranges into single ranges.
/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
-IntervalList mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);
+IntervalList
+mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);
} // end namespace IntegerIntervalUtils
diff --git a/llvm/lib/Support/IntegerInclusiveInterval.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
index c44b8b7f05446..9f5ca3636e040 100644
--- a/llvm/lib/Support/IntegerInclusiveInterval.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -78,7 +78,8 @@ bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value) {
return false;
}
-void printIntervals(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals,
+void printIntervals(raw_ostream &OS,
+ ArrayRef<IntegerInclusiveInterval> Intervals,
char Separator) {
if (Intervals.empty()) {
OS << "empty";
@@ -93,8 +94,8 @@ void printIntervals(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Interval
}
}
-IntervalList mergeAdjacentIntervals(
- ArrayRef<IntegerInclusiveInterval> Intervals) {
+IntervalList
+mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals) {
if (Intervals.empty())
return {};
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index 2de15889225a4..e156790978f34 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Program.h"
#include "llvm/Support/IntegerInclusiveInterval.h"
+#include "llvm/Support/Program.h"
using namespace llvm;
@@ -133,7 +133,6 @@ int main(int argc, char **argv) {
errs() << "Minimal Chunks = ";
IntegerIntervalUtils::printIntervals(
- llvm::errs(),
- IntegerIntervalUtils::mergeAdjacentIntervals(CurrChunks));
+ llvm::errs(), IntegerIntervalUtils::mergeAdjacentIntervals(CurrChunks));
errs() << "\n";
}
diff --git a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
index b57c779378736..3bdac7d0ee5f9 100644
--- a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
+++ b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
@@ -223,12 +223,13 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Input.clear();
Expected.clear();
Input.push_back(IntegerInclusiveInterval(1, 3));
- Input.push_back(IntegerInclusiveInterval(4, 6)); // Adjacent to first.
- Input.push_back(IntegerInclusiveInterval(8, 10)); // Gap.
- Input.push_back(IntegerInclusiveInterval(11, 13)); // Adjacent to third.
- Input.push_back(IntegerInclusiveInterval(14, 16)); // Adjacent to fourth.
- Expected.push_back(IntegerInclusiveInterval(1, 6)); // Merged 1-3 and 4-6.
- Expected.push_back(IntegerInclusiveInterval(8, 16)); // Merged 8-10, 11-13, 14-16.
+ Input.push_back(IntegerInclusiveInterval(4, 6)); // Adjacent to first.
+ Input.push_back(IntegerInclusiveInterval(8, 10)); // Gap.
+ Input.push_back(IntegerInclusiveInterval(11, 13)); // Adjacent to third.
+ Input.push_back(IntegerInclusiveInterval(14, 16)); // Adjacent to fourth.
+ Expected.push_back(IntegerInclusiveInterval(1, 6)); // Merged 1-3 and 4-6.
+ Expected.push_back(
+ IntegerInclusiveInterval(8, 16)); // Merged 8-10, 11-13, 14-16.
Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
>From e4a0cab256da474bc3ed5d3ea1a990b0f2e29d60 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 21:07:07 +0000
Subject: [PATCH 42/49] more pruning range
---
llvm/include/llvm/IR/OptBisect.h | 22 +-
llvm/include/llvm/Support/DebugCounter.h | 2 +-
.../llvm/Support/IntegerInclusiveInterval.h | 47 +++--
llvm/lib/IR/OptBisect.cpp | 34 +--
llvm/lib/Support/IntegerInclusiveInterval.cpp | 12 +-
llvm/test/Other/debugcounter-multi-ranges.ll | 116 ----------
llvm/test/Other/opt-bisect-ranges.ll | 24 +--
.../reduce-chunk-list/reduce-chunk-list.cpp | 2 +-
.../Support/IntegerInclusiveIntervalTest.cpp | 198 +++++++++---------
9 files changed, 170 insertions(+), 287 deletions(-)
delete mode 100644 llvm/test/Other/debugcounter-multi-ranges.ll
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 033107ab16468..b7b524db31714 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -14,8 +14,6 @@
#ifndef LLVM_IR_OPTBISECT_H
#define LLVM_IR_OPTBISECT_H
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
@@ -55,12 +53,12 @@ class LLVM_ABI OptBisect : public OptPassGate {
~OptBisect() override = default;
- /// Checks the bisect ranges to determine if the specified pass should run.
+ /// Checks the bisect intervals to determine if the specified pass should run.
///
/// The method prints the name of the pass, its assigned bisect number, and
/// whether or not the pass will be executed. It returns true if the pass
- /// should run, i.e. if no ranges are specified or the current pass number
- /// falls within one of the specified ranges.
+ /// should run, i.e. if no intervals are specified or the current pass number
+ /// falls within one of the specified intervals.
///
/// Most passes should not call this routine directly. Instead, it is called
/// through helper routines provided by the base classes of the pass. For
@@ -69,22 +67,22 @@ class LLVM_ABI OptBisect : public OptPassGate {
StringRef IRDescription) const override;
/// isEnabled() should return true before calling shouldRunPass().
- bool isEnabled() const override { return !BisectRanges.empty(); }
+ bool isEnabled() const override { return !BisectIntervals.empty(); }
/// Set intervals directly from an IntervalList.
- void setRanges(IntegerIntervalUtils::IntervalList Ranges) {
- BisectRanges = std::move(Ranges);
+ void setIntervals(IntegerIntervalUtils::IntervalList Intervals) {
+ BisectIntervals = std::move(Intervals);
}
- /// Clear all ranges, effectively disabling bisection.
- void clearRanges() {
- BisectRanges.clear();
+ /// Clear all intervals, effectively disabling bisection.
+ void clearIntervals() {
+ BisectIntervals.clear();
LastBisectNum = 0;
}
private:
mutable int LastBisectNum = 0;
- IntegerIntervalUtils::IntervalList BisectRanges;
+ IntegerIntervalUtils::IntervalList BisectIntervals;
};
/// This class implements a mechanism to disable passes and individual
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index 2115995f6b190..8901c5e714d16 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -17,7 +17,7 @@
/// 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 list of chunks (inclusive numeric ranges). `shouldExecute`
+/// consists of a list of chunks (inclusive numeric intervals). `shouldExecute`
/// returns true iff the list is empty or the current count is in one of the
/// chunks.
///
diff --git a/llvm/include/llvm/Support/IntegerInclusiveInterval.h b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
index 592ad127cf7bd..6edf78edb938c 100644
--- a/llvm/include/llvm/Support/IntegerInclusiveInterval.h
+++ b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
@@ -1,4 +1,4 @@
-//===- llvm/Support/Range.h - Range parsing utility -----------*- C++ -*-===//
+//===- llvm/Support/IntegerInclusiveInterval.h - Integer inclusive interval parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,13 +6,14 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides utilities for parsing range specifications like
-// "1-10,20-30,45" which are commonly used in debugging and bisection tools.
+// This file provides utilities for parsing interval specifications like
+// "1-10,20-30,45" which are commonly used in debugging and bisection tools,
+// but the same utilities can be used for any other type of interval.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_SUPPORT_RANGE_H
-#define LLVM_SUPPORT_RANGE_H
+#ifndef LLVM_SUPPORT_INTEGER_INCLUSIVE_INTERVAL_H
+#define LLVM_SUPPORT_INTEGER_INCLUSIVE_INTERVAL_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
@@ -36,7 +37,7 @@ class IntegerInclusiveInterval {
/// Create an interval [Begin, End].
IntegerInclusiveInterval(int64_t Begin, int64_t End)
: Begin(Begin), End(End) {
- assert(Begin <= End && "Range Begin must be <= End");
+ assert(Begin <= End && "Interval Begin must be <= End");
}
/// Create a singleton interval [Single, Single].
IntegerInclusiveInterval(int64_t Single) : Begin(Single), End(Single) {}
@@ -45,23 +46,23 @@ class IntegerInclusiveInterval {
int64_t getEnd() const { return End; }
void setBegin(int64_t NewBegin) {
- assert(NewBegin <= End && "Range Begin must be <= End");
+ assert(NewBegin <= End && "Interval Begin must be <= End");
Begin = NewBegin;
}
void setEnd(int64_t NewEnd) {
- assert(Begin <= NewEnd && "Range Begin must be <= End");
+ assert(Begin <= NewEnd && "Interval Begin must be <= End");
End = NewEnd;
}
- /// Check if the given value is within this range (inclusive).
+ /// Check if the given value is within this interval (inclusive).
bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }
- /// Check if this range overlaps with another range.
+ /// Check if this interval overlaps with another interval.
bool overlaps(const IntegerInclusiveInterval &Other) const {
return Begin <= Other.End && End >= Other.Begin;
}
- /// Print the range to the output stream.
+ /// Print the interval to the output stream.
void print(raw_ostream &OS) const {
if (Begin == End)
OS << Begin;
@@ -76,30 +77,30 @@ class IntegerInclusiveInterval {
namespace IntegerIntervalUtils {
-/// A list of integer ranges.
+/// A list of integer intervals.
using IntervalList = SmallVector<IntegerInclusiveInterval, 8>;
-/// Parse a range specification string like "1-10,20-30,45" or
-/// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping.
-/// \param RangeStr The string to parse.
+/// Parse a interval specification string like "1-10,20-30,45" or
+/// "1-10:20-30:45". Intervals must be in increasing order and non-overlapping.
+/// \param IntervalStr The string to parse.
/// \param Separator The separator character to use (',' or ':').
-/// \returns Expected<RangeList> containing the parsed ranges on success,
+/// \returns Expected<IntervalList> containing the parsed intervals on success,
/// or an Error on failure.
-Expected<IntervalList> parseIntervals(StringRef RangeStr, char Separator = ',');
+Expected<IntervalList> parseIntervals(StringRef IntervalStr, char Separator = ',');
-/// Check if a value is contained in any of the ranges.
+/// Check if a value is contained in any of the intervals.
bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);
-/// Print ranges to output stream.
+/// Print intervals to output stream.
/// \param OS The output stream to print to.
-/// \param Ranges The ranges to print.
-/// \param Separator The separator character to use between ranges (i.e. ',' or
+/// \param Intervals The intervals to print.
+/// \param Separator The separator character to use between intervals (i.e. ',' or
/// ':').
void printIntervals(raw_ostream &OS,
ArrayRef<IntegerInclusiveInterval> Intervals,
char Separator = ',');
-/// Merge adjacent/consecutive ranges into single ranges.
+/// Merge adjacent/consecutive intervals into single intervals.
/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
IntervalList
mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);
@@ -108,4 +109,4 @@ mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);
} // end namespace llvm
-#endif // LLVM_SUPPORT_RANGE_H
+#endif // LLVM_SUPPORT_INTEGER_INCLUSIVE_INTERVAL_H
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index decdf971735ff..a41e32855494e 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -38,13 +38,13 @@ static cl::opt<int> OptBisectLimit(
cl::cb<void, int>([](int Limit) {
if (Limit == -1)
// -1 means run all passes.
- getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
+ getOptBisector().setIntervals({{1, std::numeric_limits<int>::max()}});
else if (Limit == 0)
// 0 means run no passes.
- getOptBisector().setRanges({{0, 0}});
+ getOptBisector().setIntervals({{0, 0}});
else if (Limit > 0)
- // Convert limit to range 1-Limit.
- getOptBisector().setRanges({{1, Limit}});
+ // Convert limit to interval 1-Limit.
+ getOptBisector().setIntervals({{1, Limit}});
else
llvm_unreachable(
("Invalid limit for -opt-bisect-limit: " + llvm::utostr(Limit))
@@ -53,26 +53,26 @@ static cl::opt<int> OptBisectLimit(
cl::desc(
"Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
-static cl::opt<std::string> OptBisectRanges(
+static cl::opt<std::string> OptBisectIntervals(
"opt-bisect", cl::Hidden, cl::Optional,
- cl::cb<void, const std::string &>([](const std::string &RangeStr) {
- if (RangeStr == "-1") {
+ cl::cb<void, const std::string &>([](const std::string &IntervalStr) {
+ if (IntervalStr == "-1") {
// -1 means run all passes.
- getOptBisector().setRanges({{1, std::numeric_limits<int>::max()}});
+ getOptBisector().setIntervals({{1, std::numeric_limits<int>::max()}});
return;
}
- auto Ranges = IntegerIntervalUtils::parseIntervals(RangeStr);
- if (!Ranges) {
- handleAllErrors(Ranges.takeError(), [&](const StringError &E) {
- errs() << "Error: Invalid range specification for -opt-bisect: "
- << RangeStr << " (" << E.getMessage() << ")\n";
+ auto Intervals = IntegerIntervalUtils::parseIntervals(IntervalStr);
+ if (!Intervals) {
+ handleAllErrors(Intervals.takeError(), [&](const StringError &E) {
+ errs() << "Error: Invalid interval specification for -opt-bisect: "
+ << IntervalStr << " (" << E.getMessage() << ")\n";
});
exit(1);
}
- getOptBisector().setRanges(std::move(*Ranges));
+ getOptBisector().setIntervals(std::move(*Intervals));
}),
- cl::desc("Run optimization passes only for the specified ranges. "
+ cl::desc("Run optimization passes only for the specified intervals. "
"Format: '1-10,20-30,45' runs passes 1-10, 20-30, and 45, where "
"index 1 is the first pass. Supply '0' to run no passes and -1 to "
"run all passes."));
@@ -107,8 +107,8 @@ bool OptBisect::shouldRunPass(StringRef PassName,
int CurBisectNum = ++LastBisectNum;
- // Check if current pass number falls within any of the specified ranges.
- bool ShouldRun = IntegerIntervalUtils::contains(BisectRanges, CurBisectNum);
+ // Check if current pass number falls within any of the specified intervals.
+ bool ShouldRun = IntegerIntervalUtils::contains(BisectIntervals, CurBisectNum);
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
diff --git a/llvm/lib/Support/IntegerInclusiveInterval.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
index 9f5ca3636e040..87b41bf6c1f8b 100644
--- a/llvm/lib/Support/IntegerInclusiveInterval.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -1,4 +1,4 @@
-//===- llvm/Support/Range.cpp - Range parsing utility ---------*- C++ -*-===//
+//===- llvm/Support/IntegerInclusiveInterval.cpp - Integer inclusive interval parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -25,7 +25,7 @@ Expected<IntervalList> parseIntervals(StringRef Str, char Separator) {
return std::move(Intervals);
// Regex to match either single number or interval "num1-num2".
- const Regex RangeRegex("^([0-9]+)(-([0-9]+))?$");
+ const Regex IntervalRegex("^([0-9]+)(-([0-9]+))?$");
for (StringRef Part : llvm::split(Str, Separator)) {
Part = Part.trim();
@@ -33,9 +33,9 @@ Expected<IntervalList> parseIntervals(StringRef Str, char Separator) {
continue;
SmallVector<StringRef, 4> Matches;
- if (!RangeRegex.match(Part, &Matches))
+ if (!IntervalRegex.match(Part, &Matches))
return createStringError(std::errc::invalid_argument,
- "Invalid range format: '%s'",
+ "Invalid interval format: '%s'",
Part.str().c_str());
int64_t Begin, End;
@@ -45,14 +45,14 @@ Expected<IntervalList> parseIntervals(StringRef Str, char Separator) {
Matches[1].str().c_str());
if (!Matches[3].empty()) {
- // Range format "begin-end".
+ // Interval format "begin-end".
if (Matches[3].getAsInteger(10, End))
return createStringError(std::errc::invalid_argument,
"Failed to parse number: '%s'",
Matches[3].str().c_str());
if (Begin >= End)
return createStringError(std::errc::invalid_argument,
- "Invalid range: %lld >= %lld", Begin, End);
+ "Invalid interval: %lld >= %lld", Begin, End);
} else
// Single number.
End = Begin;
diff --git a/llvm/test/Other/debugcounter-multi-ranges.ll b/llvm/test/Other/debugcounter-multi-ranges.ll
deleted file mode 100644
index 7d9b1949a5499..0000000000000
--- a/llvm/test/Other/debugcounter-multi-ranges.ll
+++ /dev/null
@@ -1,116 +0,0 @@
-; REQUIRES: asserts
-
-; Test debug counter with multiple ranges
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=0 < %s | FileCheck %s --check-prefix=CHECK-ZERO
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=1:3:5 < %s | FileCheck %s --check-prefix=CHECK-SINGLE
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2:4:6-7 < %s | FileCheck %s --check-prefix=CHECK-MIXED
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-7 < %s | FileCheck %s --check-prefix=CHECK-ALL
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=100 < %s | FileCheck %s --check-prefix=CHECK-NONE
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=7 < %s | FileCheck %s --check-prefix=CHECK-LAST
-; RUN: opt -passes=dce -S -debug-counter=dce-transform=1 < %s | FileCheck %s --check-prefix=CHECK-FIRST
-
-; Test error cases - these should produce error messages but not crash
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=invalid 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-INVALID
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=5-2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-BACKWARDS
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:3:2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-UNORDERED
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=abc-def 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-NON-NUMERIC
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1-abc 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-MIXED
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:2:3:2:4 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-COMPLEX-UNORDERED
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1--5 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-DOUBLE-DASH
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=-5 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-NEGATIVE
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform= 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-EMPTY
-; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:1:1 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-DUPLICATE
-
-; Test that with debug counters on, we can selectively apply transformations
-; using different range specifications. Also check that we catch errors during parsing.
-
-; Original function has 8 dead instructions that DCE can eliminate
-define void @test() {
- %dead1 = add i32 1, 2
- %dead2 = add i32 3, 4
- %dead3 = add i32 5, 6
- %dead4 = add i32 7, 8
- %dead5 = add i32 9, 10
- %dead6 = add i32 11, 12
- %dead7 = add i32 13, 14
- %dead8 = add i32 15, 16
- ret void
-}
-
-; Test zero: eliminate transformation 0
-; CHECK-ZERO-LABEL: @test
-; CHECK-ZERO-NEXT: %dead2 = add i32 3, 4
-; CHECK-ZERO-NEXT: %dead3 = add i32 5, 6
-; CHECK-ZERO-NEXT: %dead4 = add i32 7, 8
-; CHECK-ZERO-NEXT: %dead5 = add i32 9, 10
-; CHECK-ZERO-NEXT: %dead6 = add i32 11, 12
-; CHECK-ZERO-NEXT: %dead7 = add i32 13, 14
-; CHECK-ZERO-NEXT: %dead8 = add i32 15, 16
-; CHECK-ZERO-NEXT: ret void
-
-; Test single values: apply transformations 1, 3, 5 (eliminate dead2, dead4, dead6)
-; CHECK-SINGLE-LABEL: @test
-; CHECK-SINGLE-NEXT: %dead1 = add i32 1, 2
-; CHECK-SINGLE-NEXT: %dead3 = add i32 5, 6
-; CHECK-SINGLE-NEXT: %dead5 = add i32 9, 10
-; CHECK-SINGLE-NEXT: %dead7 = add i32 13, 14
-; CHECK-SINGLE-NEXT: %dead8 = add i32 15, 16
-; CHECK-SINGLE-NEXT: ret void
-
-; Test mixed ranges: apply transformations 1-2, 4, 6-7 (eliminate dead2, dead3, dead5, dead7, dead8)
-; CHECK-MIXED-LABEL: @test
-; CHECK-MIXED-NEXT: %dead1 = add i32 1, 2
-; CHECK-MIXED-NEXT: %dead4 = add i32 7, 8
-; CHECK-MIXED-NEXT: %dead6 = add i32 11, 12
-; CHECK-MIXED-NEXT: ret void
-
-; Test all range: apply transformations 1-7 (eliminate all dead instructions except dead1)
-; CHECK-ALL-LABEL: @test
-; CHECK-ALL-NEXT: %dead1 = add i32 1, 2
-; CHECK-ALL-NEXT: ret void
-
-; Test out of range: apply transformation 100 (eliminate nothing, counter too high)
-; CHECK-NONE-LABEL: @test
-; CHECK-NONE-NEXT: %dead1 = add i32 1, 2
-; CHECK-NONE-NEXT: %dead2 = add i32 3, 4
-; CHECK-NONE-NEXT: %dead3 = add i32 5, 6
-; CHECK-NONE-NEXT: %dead4 = add i32 7, 8
-; CHECK-NONE-NEXT: %dead5 = add i32 9, 10
-; CHECK-NONE-NEXT: %dead6 = add i32 11, 12
-; CHECK-NONE-NEXT: %dead7 = add i32 13, 14
-; CHECK-NONE-NEXT: %dead8 = add i32 15, 16
-; CHECK-NONE-NEXT: ret void
-
-; Test last transformation: apply transformation 7 (eliminate dead8)
-; CHECK-LAST-LABEL: @test
-; CHECK-LAST-NEXT: %dead1 = add i32 1, 2
-; CHECK-LAST-NEXT: %dead2 = add i32 3, 4
-; CHECK-LAST-NEXT: %dead3 = add i32 5, 6
-; CHECK-LAST-NEXT: %dead4 = add i32 7, 8
-; CHECK-LAST-NEXT: %dead5 = add i32 9, 10
-; CHECK-LAST-NEXT: %dead6 = add i32 11, 12
-; CHECK-LAST-NEXT: %dead7 = add i32 13, 14
-; CHECK-LAST-NEXT: ret void
-
-; Test first transformation: apply transformation 1 (eliminate dead2)
-; CHECK-FIRST-LABEL: @test
-; CHECK-FIRST-NEXT: %dead1 = add i32 1, 2
-; CHECK-FIRST-NEXT: %dead3 = add i32 5, 6
-; CHECK-FIRST-NEXT: %dead4 = add i32 7, 8
-; CHECK-FIRST-NEXT: %dead5 = add i32 9, 10
-; CHECK-FIRST-NEXT: %dead6 = add i32 11, 12
-; CHECK-FIRST-NEXT: %dead7 = add i32 13, 14
-; CHECK-FIRST-NEXT: %dead8 = add i32 15, 16
-; CHECK-FIRST-NEXT: ret void
-
-; Error case checks - test comprehensive error handling
-; CHECK-ERROR-INVALID: DebugCounter Error: Invalid range format: 'invalid'
-; CHECK-ERROR-BACKWARDS: DebugCounter Error: Invalid range: 5 >= 2
-; CHECK-ERROR-UNORDERED: DebugCounter Error: Expected ranges to be in increasing order: 2 <= 3
-; CHECK-ERROR-NON-NUMERIC: DebugCounter Error: Invalid range format: 'abc-def'
-; CHECK-ERROR-MIXED: DebugCounter Error: Invalid range format: '1-abc'
-; CHECK-ERROR-COMPLEX-UNORDERED: DebugCounter Error: Expected ranges to be in increasing order: 2 <= 3
-; CHECK-ERROR-DOUBLE-DASH: DebugCounter Error: Invalid range format: '1--5'
-; CHECK-ERROR-NEGATIVE: DebugCounter Error: Invalid range format: '-5'
-; CHECK-ERROR-EMPTY: DebugCounter Error: dce-transform= does not have an = in it
-; CHECK-ERROR-DUPLICATE: DebugCounter Error: Expected ranges to be in increasing order: 1 <= 1
diff --git a/llvm/test/Other/opt-bisect-ranges.ll b/llvm/test/Other/opt-bisect-ranges.ll
index 84b2d336f6f6e..2738ef8a584dc 100644
--- a/llvm/test/Other/opt-bisect-ranges.ll
+++ b/llvm/test/Other/opt-bisect-ranges.ll
@@ -1,20 +1,20 @@
-; Test that verifies functionality for -opt-bisect with range specifications
+; Test that verifies functionality for -opt-bisect with interval specifications
-; Test basic range functionality: run passes 1-3 and 7-8
+; Test basic interval functionality: run passes 1-3 and 7-8
; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
-; RUN: -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-RANGES
-; CHECK-RANGES: BISECT: running pass (1) annotation2metadata on [module]
-; CHECK-RANGES: BISECT: running pass (2) forceattrs on [module]
-; CHECK-RANGES: BISECT: running pass (3) inferattrs on [module]
-; CHECK-RANGES: BISECT: NOT running pass (4) lower-expect on foo
-; CHECK-RANGES: BISECT: NOT running pass (5) simplifycfg on foo
-; CHECK-RANGES: BISECT: NOT running pass (6) sroa on foo
-; CHECK-RANGES: BISECT: running pass (7) early-cse on foo
-; CHECK-RANGES: BISECT: running pass (8) openmp-opt on [module]
+; RUN: -opt-bisect=1-3,7-8 %s 2>&1 | FileCheck %s --check-prefix=CHECK-INTERVALS
+; CHECK-INTERVALS: BISECT: running pass (1) annotation2metadata on [module]
+; CHECK-INTERVALS: BISECT: running pass (2) forceattrs on [module]
+; CHECK-INTERVALS: BISECT: running pass (3) inferattrs on [module]
+; CHECK-INTERVALS: BISECT: NOT running pass (4) lower-expect on foo
+; CHECK-INTERVALS: BISECT: NOT running pass (5) simplifycfg on foo
+; CHECK-INTERVALS: BISECT: NOT running pass (6) sroa on foo
+; CHECK-INTERVALS: BISECT: running pass (7) early-cse on foo
+; CHECK-INTERVALS: BISECT: running pass (8) openmp-opt on [module]
; Test single pass selection: run only pass 5
; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
-; RUN: -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE
+; RUN: -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE-INTERVAL
; CHECK-SINGLE: BISECT: NOT running pass (1) annotation2metadata on [module]
; CHECK-SINGLE: BISECT: NOT running pass (2) forceattrs on [module]
; CHECK-SINGLE: BISECT: NOT running pass (3) inferattrs on [module]
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index e156790978f34..8b386ab646cf5 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -116,7 +116,7 @@ int main(int argc, char **argv) {
if (CurrChunks.size() == 1)
break;
- Range Testing = CurrChunks[Idx];
+ IntegerInclusiveInterval Testing = CurrChunks[Idx];
errs() << "Trying to remove : ";
Testing.print(errs());
errs() << "\n";
diff --git a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
index 3bdac7d0ee5f9..7f9befbb1d204 100644
--- a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
+++ b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
@@ -1,4 +1,4 @@
-//===- llvm/unittests/Support/RangeTest.cpp - Range tests ----------------===//
+//===- llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp - Integer inclusive interval tests ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -13,90 +13,90 @@
using namespace llvm;
TEST(IntegerInclusiveIntervalTest, BasicInterval) {
- IntegerInclusiveInterval R(5, 10);
- EXPECT_EQ(R.getBegin(), 5);
- EXPECT_EQ(R.getEnd(), 10);
- EXPECT_TRUE(R.contains(5));
- EXPECT_TRUE(R.contains(7));
- EXPECT_TRUE(R.contains(10));
- EXPECT_FALSE(R.contains(4));
- EXPECT_FALSE(R.contains(11));
+ IntegerInclusiveInterval I(5, 10);
+ EXPECT_EQ(I.getBegin(), 5);
+ EXPECT_EQ(I.getEnd(), 10);
+ EXPECT_TRUE(I.contains(5));
+ EXPECT_TRUE(I.contains(7));
+ EXPECT_TRUE(I.contains(10));
+ EXPECT_FALSE(I.contains(4));
+ EXPECT_FALSE(I.contains(11));
}
TEST(IntegerInclusiveIntervalTest, SingleValueInterval) {
- IntegerInclusiveInterval R(42);
- EXPECT_EQ(R.getBegin(), 42);
- EXPECT_EQ(R.getEnd(), 42);
- EXPECT_TRUE(R.contains(42));
- EXPECT_FALSE(R.contains(41));
- EXPECT_FALSE(R.contains(43));
+ IntegerInclusiveInterval I(42);
+ EXPECT_EQ(I.getBegin(), 42);
+ EXPECT_EQ(I.getEnd(), 42);
+ EXPECT_TRUE(I.contains(42));
+ EXPECT_FALSE(I.contains(41));
+ EXPECT_FALSE(I.contains(43));
}
TEST(IntegerInclusiveIntervalTest, IntervalOverlaps) {
- IntegerInclusiveInterval R1(1, 5);
- IntegerInclusiveInterval R2(3, 8);
- IntegerInclusiveInterval R3(6, 10);
- IntegerInclusiveInterval R4(11, 15);
-
- EXPECT_TRUE(R1.overlaps(R2));
- EXPECT_TRUE(R2.overlaps(R1));
- EXPECT_TRUE(R2.overlaps(R3));
- EXPECT_FALSE(R1.overlaps(R3));
- EXPECT_FALSE(R1.overlaps(R4));
- EXPECT_FALSE(R3.overlaps(R4));
+ IntegerInclusiveInterval I1(1, 5);
+ IntegerInclusiveInterval I2(3, 8);
+ IntegerInclusiveInterval I3(6, 10);
+ IntegerInclusiveInterval I4(11, 15);
+
+ EXPECT_TRUE(I1.overlaps(I2));
+ EXPECT_TRUE(I2.overlaps(I1));
+ EXPECT_TRUE(I2.overlaps(I3));
+ EXPECT_FALSE(I1.overlaps(I3));
+ EXPECT_FALSE(I1.overlaps(I4));
+ EXPECT_FALSE(I3.overlaps(I4));
}
TEST(IntegerIntervalUtilsTest, ParseSingleNumber) {
auto ER = IntegerIntervalUtils::parseIntervals("42");
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 1U);
- EXPECT_EQ(Ranges[0].getBegin(), 42);
- EXPECT_EQ(Ranges[0].getEnd(), 42);
+ auto Intervals = std::move(*ER);
+ EXPECT_EQ(Intervals.size(), 1U);
+ EXPECT_EQ(Intervals[0].getBegin(), 42);
+ EXPECT_EQ(Intervals[0].getEnd(), 42);
}
TEST(IntegerIntervalUtilsTest, ParseSingleInterval) {
auto ER = IntegerIntervalUtils::parseIntervals("10-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 1U);
- EXPECT_EQ(Ranges[0].getBegin(), 10);
- EXPECT_EQ(Ranges[0].getEnd(), 20);
+ auto Intervals = std::move(*ER);
+ EXPECT_EQ(Intervals.size(), 1U);
+ EXPECT_EQ(Intervals[0].getBegin(), 10);
+ EXPECT_EQ(Intervals[0].getEnd(), 20);
}
TEST(IntegerIntervalUtilsTest, ParseMultipleIntervals) {
auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 3U);
-
- // Ranges are in input order (DebugCounter style).
- EXPECT_EQ(Ranges[0].getBegin(), 1);
- EXPECT_EQ(Ranges[0].getEnd(), 5);
- EXPECT_EQ(Ranges[1].getBegin(), 10);
- EXPECT_EQ(Ranges[1].getEnd(), 10);
- EXPECT_EQ(Ranges[2].getBegin(), 15);
- EXPECT_EQ(Ranges[2].getEnd(), 20);
+ auto Intervals = std::move(*ER);
+ EXPECT_EQ(Intervals.size(), 3U);
+
+ // Intervals are in input order (DebugCounter style).
+ EXPECT_EQ(Intervals[0].getBegin(), 1);
+ EXPECT_EQ(Intervals[0].getEnd(), 5);
+ EXPECT_EQ(Intervals[1].getBegin(), 10);
+ EXPECT_EQ(Intervals[1].getEnd(), 10);
+ EXPECT_EQ(Intervals[2].getBegin(), 15);
+ EXPECT_EQ(Intervals[2].getEnd(), 20);
}
TEST(IntegerIntervalUtilsTest, ParseColonSeparatedIntervals) {
auto ER = IntegerIntervalUtils::parseIntervals("1-5:10:15-20", ':');
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 3U);
- EXPECT_EQ(Ranges[0].getBegin(), 1);
- EXPECT_EQ(Ranges[0].getEnd(), 5);
- EXPECT_EQ(Ranges[1].getBegin(), 10);
- EXPECT_EQ(Ranges[1].getEnd(), 10);
- EXPECT_EQ(Ranges[2].getBegin(), 15);
- EXPECT_EQ(Ranges[2].getEnd(), 20);
+ auto Intervals = std::move(*ER);
+ EXPECT_EQ(Intervals.size(), 3U);
+ EXPECT_EQ(Intervals[0].getBegin(), 1);
+ EXPECT_EQ(Intervals[0].getEnd(), 5);
+ EXPECT_EQ(Intervals[1].getBegin(), 10);
+ EXPECT_EQ(Intervals[1].getEnd(), 10);
+ EXPECT_EQ(Intervals[2].getBegin(), 15);
+ EXPECT_EQ(Intervals[2].getEnd(), 20);
}
TEST(IntegerIntervalUtilsTest, ParseEmptyString) {
auto ER = IntegerIntervalUtils::parseIntervals("");
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_TRUE(Ranges.empty());
+ auto Intervals = std::move(*ER);
+ EXPECT_TRUE(Intervals.empty());
}
TEST(IntegerIntervalUtilsTest, ParseInvalidIntervals) {
@@ -105,12 +105,12 @@ TEST(IntegerIntervalUtilsTest, ParseInvalidIntervals) {
EXPECT_THAT_EXPECTED(ER1, Failed());
consumeError(ER1.takeError());
- // Invalid range (begin > end).
+ // Invalid interval (begin > end).
auto ER2 = IntegerIntervalUtils::parseIntervals("10-5");
EXPECT_THAT_EXPECTED(ER2, Failed());
consumeError(ER2.takeError());
- // Out of order ranges (DebugCounter constraint and overlap).
+ // Out of order intervals (DebugCounter constraint and overlap).
auto ER3 = IntegerIntervalUtils::parseIntervals("10,5");
EXPECT_THAT_EXPECTED(ER3, Failed());
consumeError(ER3.takeError());
@@ -123,65 +123,65 @@ TEST(IntegerIntervalUtilsTest, ParseInvalidIntervals) {
TEST(IntegerIntervalUtilsTest, Contains) {
auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
-
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 1));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 3));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 5));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 10));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 15));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 18));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Ranges, 20));
-
- EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 6));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 9));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 11));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 14));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Ranges, 21));
+ auto Intervals = std::move(*ER);
+
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 1));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 3));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 5));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 10));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 15));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 18));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 20));
+
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 6));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 9));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 11));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 14));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 21));
}
TEST(IntegerIntervalUtilsTest, SeparatorParameter) {
- IntegerIntervalUtils::IntervalList ColonRanges, CommaRanges;
+ IntegerIntervalUtils::IntervalList ColonIntervals, CommaIntervals;
// Test explicit separator parameters.
auto ERC = IntegerIntervalUtils::parseIntervals("1-5:10:15-20", ':');
ASSERT_THAT_EXPECTED(ERC, Succeeded());
- ColonRanges = std::move(*ERC);
+ ColonIntervals = std::move(*ERC);
auto ERM = IntegerIntervalUtils::parseIntervals("1-5,10,15-20", ',');
ASSERT_THAT_EXPECTED(ERM, Succeeded());
- CommaRanges = std::move(*ERM);
+ CommaIntervals = std::move(*ERM);
- EXPECT_EQ(ColonRanges.size(), CommaRanges.size());
- for (size_t I = 0; I < ColonRanges.size(); ++I) {
- EXPECT_EQ(ColonRanges[I].getBegin(), CommaRanges[I].getBegin());
- EXPECT_EQ(ColonRanges[I].getEnd(), CommaRanges[I].getEnd());
+ EXPECT_EQ(ColonIntervals.size(), CommaIntervals.size());
+ for (size_t I = 0; I < ColonIntervals.size(); ++I) {
+ EXPECT_EQ(ColonIntervals[I].getBegin(), CommaIntervals[I].getBegin());
+ EXPECT_EQ(ColonIntervals[I].getEnd(), CommaIntervals[I].getEnd());
}
// Test that both work with contains().
- EXPECT_TRUE(IntegerIntervalUtils::contains(ColonRanges, 3));
- EXPECT_TRUE(IntegerIntervalUtils::contains(CommaRanges, 3));
- EXPECT_TRUE(IntegerIntervalUtils::contains(ColonRanges, 10));
- EXPECT_TRUE(IntegerIntervalUtils::contains(CommaRanges, 10));
- EXPECT_TRUE(IntegerIntervalUtils::contains(ColonRanges, 18));
- EXPECT_TRUE(IntegerIntervalUtils::contains(CommaRanges, 18));
-
- EXPECT_FALSE(IntegerIntervalUtils::contains(ColonRanges, 8));
- EXPECT_FALSE(IntegerIntervalUtils::contains(CommaRanges, 8));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(ColonIntervals, 3));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(CommaIntervals, 3));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(ColonIntervals, 10));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(CommaIntervals, 10));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(ColonIntervals, 18));
+ EXPECT_TRUE(IntegerIntervalUtils::contains(CommaIntervals, 18));
+
+ EXPECT_FALSE(IntegerIntervalUtils::contains(ColonIntervals, 8));
+ EXPECT_FALSE(IntegerIntervalUtils::contains(CommaIntervals, 8));
}
TEST(IntegerIntervalUtilsTest, DefaultCommaSeparator) {
// Test that comma is the default separator.
auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
- auto Ranges = std::move(*ER);
- EXPECT_EQ(Ranges.size(), 3U);
- EXPECT_EQ(Ranges[0].getBegin(), 1);
- EXPECT_EQ(Ranges[0].getEnd(), 5);
- EXPECT_EQ(Ranges[1].getBegin(), 10);
- EXPECT_EQ(Ranges[1].getEnd(), 10);
- EXPECT_EQ(Ranges[2].getBegin(), 15);
- EXPECT_EQ(Ranges[2].getEnd(), 20);
+ auto Intervals = std::move(*ER);
+ EXPECT_EQ(Intervals.size(), 3U);
+ EXPECT_EQ(Intervals[0].getBegin(), 1);
+ EXPECT_EQ(Intervals[0].getEnd(), 5);
+ EXPECT_EQ(Intervals[1].getBegin(), 10);
+ EXPECT_EQ(Intervals[1].getEnd(), 10);
+ EXPECT_EQ(Intervals[2].getBegin(), 15);
+ EXPECT_EQ(Intervals[2].getEnd(), 20);
}
TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
@@ -191,13 +191,13 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_TRUE(Result.empty());
- // Single range - no change.
+ // Single interval - no change.
Input.push_back(IntegerInclusiveInterval(5, 10));
Expected.push_back(IntegerInclusiveInterval(5, 10));
Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
- // Adjacent ranges should merge.
+ // Adjacent intervals should merge.
Input.clear();
Expected.clear();
Input.push_back(IntegerInclusiveInterval(1, 3));
@@ -207,7 +207,7 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
- // Non-adjacent ranges should not merge.
+ // Non-adjacent intervals should not merge.
Input.clear();
Expected.clear();
Input.push_back(IntegerInclusiveInterval(1, 3));
@@ -219,7 +219,7 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
- // Mixed adjacent and non-adjacent.
+ // Mixed adjacent and non-adjacent intervals.
Input.clear();
Expected.clear();
Input.push_back(IntegerInclusiveInterval(1, 3));
>From 5a7d3e63e9b93a4c815c3f2accb72e6345129db1 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 21:07:13 +0000
Subject: [PATCH 43/49] format
---
llvm/include/llvm/Support/DebugCounter.h | 2 +-
llvm/include/llvm/Support/IntegerInclusiveInterval.h | 9 ++++++---
llvm/lib/IR/OptBisect.cpp | 3 ++-
llvm/lib/Support/IntegerInclusiveInterval.cpp | 3 ++-
llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp | 3 ++-
5 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index 8901c5e714d16..f81aa11d81fb9 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -80,7 +80,7 @@ class DebugCounter {
}
};
- LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Ranges);
+ LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals);
/// Return true on parsing error and print the error message on the
/// llvm::errs()
diff --git a/llvm/include/llvm/Support/IntegerInclusiveInterval.h b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
index 6edf78edb938c..5075bc39042ce 100644
--- a/llvm/include/llvm/Support/IntegerInclusiveInterval.h
+++ b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
@@ -1,4 +1,5 @@
-//===- llvm/Support/IntegerInclusiveInterval.h - Integer inclusive interval parsing utility -----------*- C++ -*-===//
+//===- llvm/Support/IntegerInclusiveInterval.h - Integer inclusive interval
+//parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -86,7 +87,8 @@ using IntervalList = SmallVector<IntegerInclusiveInterval, 8>;
/// \param Separator The separator character to use (',' or ':').
/// \returns Expected<IntervalList> containing the parsed intervals on success,
/// or an Error on failure.
-Expected<IntervalList> parseIntervals(StringRef IntervalStr, char Separator = ',');
+Expected<IntervalList> parseIntervals(StringRef IntervalStr,
+ char Separator = ',');
/// Check if a value is contained in any of the intervals.
bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);
@@ -94,7 +96,8 @@ bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);
/// Print intervals to output stream.
/// \param OS The output stream to print to.
/// \param Intervals The intervals to print.
-/// \param Separator The separator character to use between intervals (i.e. ',' or
+/// \param Separator The separator character to use between intervals (i.e. ','
+/// or
/// ':').
void printIntervals(raw_ostream &OS,
ArrayRef<IntegerInclusiveInterval> Intervals,
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index a41e32855494e..646e212b0ee04 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -108,7 +108,8 @@ bool OptBisect::shouldRunPass(StringRef PassName,
int CurBisectNum = ++LastBisectNum;
// Check if current pass number falls within any of the specified intervals.
- bool ShouldRun = IntegerIntervalUtils::contains(BisectIntervals, CurBisectNum);
+ bool ShouldRun =
+ IntegerIntervalUtils::contains(BisectIntervals, CurBisectNum);
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
diff --git a/llvm/lib/Support/IntegerInclusiveInterval.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
index 87b41bf6c1f8b..fb76e33f06fad 100644
--- a/llvm/lib/Support/IntegerInclusiveInterval.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -1,4 +1,5 @@
-//===- llvm/Support/IntegerInclusiveInterval.cpp - Integer inclusive interval parsing utility -----------*- C++ -*-===//
+//===- llvm/Support/IntegerInclusiveInterval.cpp - Integer inclusive interval
+//parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
index 7f9befbb1d204..09e045bd0644b 100644
--- a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
+++ b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
@@ -1,4 +1,5 @@
-//===- llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp - Integer inclusive interval tests ----------------===//
+//===- llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp - Integer
+//inclusive interval tests ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
>From 887e0e080ec685bf38152c77b605f28ad4ed855d Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 23 Sep 2025 21:12:53 +0000
Subject: [PATCH 44/49] format
---
llvm/include/llvm/Support/IntegerInclusiveInterval.h | 2 +-
llvm/lib/Support/IntegerInclusiveInterval.cpp | 2 +-
llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/IntegerInclusiveInterval.h b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
index 5075bc39042ce..0b654e34a72d8 100644
--- a/llvm/include/llvm/Support/IntegerInclusiveInterval.h
+++ b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
@@ -1,5 +1,5 @@
//===- llvm/Support/IntegerInclusiveInterval.h - Integer inclusive interval
-//parsing utility -----------*- C++ -*-===//
+// parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/lib/Support/IntegerInclusiveInterval.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
index fb76e33f06fad..70c7809d06b73 100644
--- a/llvm/lib/Support/IntegerInclusiveInterval.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -1,5 +1,5 @@
//===- llvm/Support/IntegerInclusiveInterval.cpp - Integer inclusive interval
-//parsing utility -----------*- C++ -*-===//
+// parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
index 09e045bd0644b..36c439d1be716 100644
--- a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
+++ b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
@@ -1,5 +1,5 @@
//===- llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp - Integer
-//inclusive interval tests ----------------===//
+// inclusive interval tests ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
>From bd543bef127ec1f9e3ab75679d538d02572fb285 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Wed, 24 Sep 2025 18:58:25 +0000
Subject: [PATCH 45/49] fix tests
---
.../Other/debugcounter-multi-intervals.ll | 116 ++++++++++++++++++
llvm/test/Other/opt-bisect-ranges.ll | 12 +-
2 files changed, 122 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/Other/debugcounter-multi-intervals.ll
diff --git a/llvm/test/Other/debugcounter-multi-intervals.ll b/llvm/test/Other/debugcounter-multi-intervals.ll
new file mode 100644
index 0000000000000..d5b3c7ed314fb
--- /dev/null
+++ b/llvm/test/Other/debugcounter-multi-intervals.ll
@@ -0,0 +1,116 @@
+; REQUIRES: asserts
+
+; Test debug counter with multiple intervals
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=0 < %s | FileCheck %s --check-prefix=CHECK-ZERO
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1:3:5 < %s | FileCheck %s --check-prefix=CHECK-SINGLE
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-2:4:6-7 < %s | FileCheck %s --check-prefix=CHECK-MIXED
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1-7 < %s | FileCheck %s --check-prefix=CHECK-ALL
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=100 < %s | FileCheck %s --check-prefix=CHECK-NONE
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=7 < %s | FileCheck %s --check-prefix=CHECK-LAST
+; RUN: opt -passes=dce -S -debug-counter=dce-transform=1 < %s | FileCheck %s --check-prefix=CHECK-FIRST
+
+; Test error cases - these should produce error messages but not crash
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=invalid 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-INVALID
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=5-2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-BACKWARDS
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:3:2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-UNORDERED
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=abc-def 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-NON-NUMERIC
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1-abc 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-MIXED
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:2:3:2:4 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-COMPLEX-UNORDERED
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1--5 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-DOUBLE-DASH
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=-5 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-NEGATIVE
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform= 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-EMPTY
+; RUN: not opt -passes=dce -S -debug-counter=dce-transform=1:1:1 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-DUPLICATE
+
+; Test that with debug counters on, we can selectively apply transformations
+; using different interval specifications. Also check that we catch errors during parsing.
+
+; Original function has 8 dead instructions that DCE can eliminate
+define void @test() {
+ %dead1 = add i32 1, 2
+ %dead2 = add i32 3, 4
+ %dead3 = add i32 5, 6
+ %dead4 = add i32 7, 8
+ %dead5 = add i32 9, 10
+ %dead6 = add i32 11, 12
+ %dead7 = add i32 13, 14
+ %dead8 = add i32 15, 16
+ ret void
+}
+
+; Test zero: eliminate transformation 0
+; CHECK-ZERO-LABEL: @test
+; CHECK-ZERO-NEXT: %dead2 = add i32 3, 4
+; CHECK-ZERO-NEXT: %dead3 = add i32 5, 6
+; CHECK-ZERO-NEXT: %dead4 = add i32 7, 8
+; CHECK-ZERO-NEXT: %dead5 = add i32 9, 10
+; CHECK-ZERO-NEXT: %dead6 = add i32 11, 12
+; CHECK-ZERO-NEXT: %dead7 = add i32 13, 14
+; CHECK-ZERO-NEXT: %dead8 = add i32 15, 16
+; CHECK-ZERO-NEXT: ret void
+
+; Test single values: apply transformations 1, 3, 5 (eliminate dead2, dead4, dead6)
+; CHECK-SINGLE-LABEL: @test
+; CHECK-SINGLE-NEXT: %dead1 = add i32 1, 2
+; CHECK-SINGLE-NEXT: %dead3 = add i32 5, 6
+; CHECK-SINGLE-NEXT: %dead5 = add i32 9, 10
+; CHECK-SINGLE-NEXT: %dead7 = add i32 13, 14
+; CHECK-SINGLE-NEXT: %dead8 = add i32 15, 16
+; CHECK-SINGLE-NEXT: ret void
+
+; Test mixed intervals: apply transformations 1-2, 4, 6-7 (eliminate dead2, dead3, dead5, dead7, dead8)
+; CHECK-MIXED-LABEL: @test
+; CHECK-MIXED-NEXT: %dead1 = add i32 1, 2
+; CHECK-MIXED-NEXT: %dead4 = add i32 7, 8
+; CHECK-MIXED-NEXT: %dead6 = add i32 11, 12
+; CHECK-MIXED-NEXT: ret void
+
+; Test all interval: apply transformations 1-7 (eliminate all dead instructions except dead1)
+; CHECK-ALL-LABEL: @test
+; CHECK-ALL-NEXT: %dead1 = add i32 1, 2
+; CHECK-ALL-NEXT: ret void
+
+; Test out of interval: apply transformation 100 (eliminate nothing, counter too high)
+; CHECK-NONE-LABEL: @test
+; CHECK-NONE-NEXT: %dead1 = add i32 1, 2
+; CHECK-NONE-NEXT: %dead2 = add i32 3, 4
+; CHECK-NONE-NEXT: %dead3 = add i32 5, 6
+; CHECK-NONE-NEXT: %dead4 = add i32 7, 8
+; CHECK-NONE-NEXT: %dead5 = add i32 9, 10
+; CHECK-NONE-NEXT: %dead6 = add i32 11, 12
+; CHECK-NONE-NEXT: %dead7 = add i32 13, 14
+; CHECK-NONE-NEXT: %dead8 = add i32 15, 16
+; CHECK-NONE-NEXT: ret void
+
+; Test last transformation: apply transformation 7 (eliminate dead8)
+; CHECK-LAST-LABEL: @test
+; CHECK-LAST-NEXT: %dead1 = add i32 1, 2
+; CHECK-LAST-NEXT: %dead2 = add i32 3, 4
+; CHECK-LAST-NEXT: %dead3 = add i32 5, 6
+; CHECK-LAST-NEXT: %dead4 = add i32 7, 8
+; CHECK-LAST-NEXT: %dead5 = add i32 9, 10
+; CHECK-LAST-NEXT: %dead6 = add i32 11, 12
+; CHECK-LAST-NEXT: %dead7 = add i32 13, 14
+; CHECK-LAST-NEXT: ret void
+
+; Test first transformation: apply transformation 1 (eliminate dead2)
+; CHECK-FIRST-LABEL: @test
+; CHECK-FIRST-NEXT: %dead1 = add i32 1, 2
+; CHECK-FIRST-NEXT: %dead3 = add i32 5, 6
+; CHECK-FIRST-NEXT: %dead4 = add i32 7, 8
+; CHECK-FIRST-NEXT: %dead5 = add i32 9, 10
+; CHECK-FIRST-NEXT: %dead6 = add i32 11, 12
+; CHECK-FIRST-NEXT: %dead7 = add i32 13, 14
+; CHECK-FIRST-NEXT: %dead8 = add i32 15, 16
+; CHECK-FIRST-NEXT: ret void
+
+; Error case checks - test comprehensive error handling
+; CHECK-ERROR-INVALID: DebugCounter Error: Invalid interval format: 'invalid'
+; CHECK-ERROR-BACKWARDS: DebugCounter Error: Invalid interval: 5 >= 2
+; CHECK-ERROR-UNORDERED: DebugCounter Error: Expected intervals to be in increasing order: 2 <= 3
+; CHECK-ERROR-NON-NUMERIC: DebugCounter Error: Invalid interval format: 'abc-def'
+; CHECK-ERROR-MIXED: DebugCounter Error: Invalid interval format: '1-abc'
+; CHECK-ERROR-COMPLEX-UNORDERED: DebugCounter Error: Expected intervals to be in increasing order: 2 <= 3
+; CHECK-ERROR-DOUBLE-DASH: DebugCounter Error: Invalid interval format: '1--5'
+; CHECK-ERROR-NEGATIVE: DebugCounter Error: Invalid interval format: '-5'
+; CHECK-ERROR-EMPTY: DebugCounter Error: dce-transform= does not have an = in it
+; CHECK-ERROR-DUPLICATE: DebugCounter Error: Expected intervals to be in increasing order: 1 <= 1
diff --git a/llvm/test/Other/opt-bisect-ranges.ll b/llvm/test/Other/opt-bisect-ranges.ll
index 2738ef8a584dc..0558bb67c799c 100644
--- a/llvm/test/Other/opt-bisect-ranges.ll
+++ b/llvm/test/Other/opt-bisect-ranges.ll
@@ -15,12 +15,12 @@
; Test single pass selection: run only pass 5
; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
; RUN: -opt-bisect=5 %s 2>&1 | FileCheck %s --check-prefix=CHECK-SINGLE-INTERVAL
-; CHECK-SINGLE: BISECT: NOT running pass (1) annotation2metadata on [module]
-; CHECK-SINGLE: BISECT: NOT running pass (2) forceattrs on [module]
-; CHECK-SINGLE: BISECT: NOT running pass (3) inferattrs on [module]
-; CHECK-SINGLE: BISECT: NOT running pass (4) lower-expect on foo
-; CHECK-SINGLE: BISECT: running pass (5) simplifycfg on foo
-; CHECK-SINGLE: BISECT: NOT running pass (6) sroa on foo
+; CHECK-SINGLE-INTERVAL: BISECT: NOT running pass (1) annotation2metadata on [module]
+; CHECK-SINGLE-INTERVAL: BISECT: NOT running pass (2) forceattrs on [module]
+; CHECK-SINGLE-INTERVAL: BISECT: NOT running pass (3) inferattrs on [module]
+; CHECK-SINGLE-INTERVAL: BISECT: NOT running pass (4) lower-expect on foo
+; CHECK-SINGLE-INTERVAL: BISECT: running pass (5) simplifycfg on foo
+; CHECK-SINGLE-INTERVAL: BISECT: NOT running pass (6) sroa on foo
; Test running no passes
; RUN: opt -passes='annotation2metadata,forceattrs,inferattrs,function(lower-expect),function(simplifycfg),function(sroa),function(early-cse),openmp-opt' \
>From 875a4b1cb84cdadc55463da20888aac5d65dd702 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 11 Dec 2025 23:33:14 +0000
Subject: [PATCH 46/49] renaming
---
llvm/lib/Support/DebugCounter.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index ef0fd545db3af..5b2ca5842a68f 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -11,8 +11,8 @@ using namespace llvm;
namespace llvm {
void DebugCounter::printChunks(raw_ostream &OS,
- ArrayRef<IntegerInclusiveInterval> Ranges) {
- IntegerIntervalUtils::printIntervals(OS, Ranges, ':');
+ ArrayRef<IntegerInclusiveInterval> Chunks) {
+ IntegerIntervalUtils::printIntervals(OS, Chunks, ':');
}
} // namespace llvm
>From bd702720b77e4979f95bf0b7875b9bc80c6b40e8 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 11 Dec 2025 23:33:24 +0000
Subject: [PATCH 47/49] format
---
llvm/include/llvm/Support/DebugCounter.h | 6 ++++--
llvm/lib/Support/DebugCounter.cpp | 3 ++-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index f81aa11d81fb9..cca771b3a2925 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -80,11 +80,13 @@ class DebugCounter {
}
};
- LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals);
+ LLVM_ABI static void
+ printChunks(raw_ostream &OS, ArrayRef<IntegerInclusiveInterval> Intervals);
/// Return true on parsing error and print the error message on the
/// llvm::errs()
- LLVM_ABI static bool parseChunks(StringRef Str, IntegerIntervalUtils::IntervalList &Res);
+ LLVM_ABI static bool parseChunks(StringRef Str,
+ IntegerIntervalUtils::IntervalList &Res);
/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 5b2ca5842a68f..e81f683dc523c 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -133,7 +133,8 @@ void DebugCounter::push_back(const std::string &Val) {
return;
}
- auto ExpectedChunks = IntegerIntervalUtils::parseIntervals(CounterPair.second, ':');
+ auto ExpectedChunks =
+ IntegerIntervalUtils::parseIntervals(CounterPair.second, ':');
if (!ExpectedChunks) {
handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
errs() << "DebugCounter Error: " << E.getMessage() << "\n";
>From e4c5bb147b8a3912f19db24a7cadea898ff32a19 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 30 Dec 2025 17:41:33 +0000
Subject: [PATCH 48/49] nits
---
llvm/include/llvm/IR/OptBisect.h | 4 +-
llvm/include/llvm/Support/DebugCounter.h | 4 +-
.../llvm/Support/IntegerInclusiveInterval.h | 4 +-
llvm/lib/IR/OptBisect.cpp | 4 +-
llvm/lib/Support/DebugCounter.cpp | 4 +-
llvm/lib/Support/IntegerInclusiveInterval.cpp | 15 +--
.../reduce-chunk-list/reduce-chunk-list.cpp | 18 +--
.../Support/IntegerInclusiveIntervalTest.cpp | 107 +++++++++---------
8 files changed, 80 insertions(+), 80 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index b7b524db31714..77c866ab76d21 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -70,7 +70,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
bool isEnabled() const override { return !BisectIntervals.empty(); }
/// Set intervals directly from an IntervalList.
- void setIntervals(IntegerIntervalUtils::IntervalList Intervals) {
+ void setIntervals(IntegerInclusiveIntervalUtils::IntervalList Intervals) {
BisectIntervals = std::move(Intervals);
}
@@ -82,7 +82,7 @@ class LLVM_ABI OptBisect : public OptPassGate {
private:
mutable int LastBisectNum = 0;
- IntegerIntervalUtils::IntervalList BisectIntervals;
+ IntegerInclusiveIntervalUtils::IntervalList BisectIntervals;
};
/// This class implements a mechanism to disable passes and individual
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index cca771b3a2925..ce22f65eb29b6 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -72,7 +72,7 @@ class DebugCounter {
uint64_t CurrChunkIdx = 0;
StringRef Name;
StringRef Desc;
- IntegerIntervalUtils::IntervalList Chunks;
+ IntegerInclusiveIntervalUtils::IntervalList Chunks;
public:
CounterInfo(StringRef Name, StringRef Desc) : Name(Name), Desc(Desc) {
@@ -86,7 +86,7 @@ class DebugCounter {
/// Return true on parsing error and print the error message on the
/// llvm::errs()
LLVM_ABI static bool parseChunks(StringRef Str,
- IntegerIntervalUtils::IntervalList &Res);
+ IntegerInclusiveIntervalUtils::IntervalList &Res);
/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
diff --git a/llvm/include/llvm/Support/IntegerInclusiveInterval.h b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
index 0b654e34a72d8..28fab9466851f 100644
--- a/llvm/include/llvm/Support/IntegerInclusiveInterval.h
+++ b/llvm/include/llvm/Support/IntegerInclusiveInterval.h
@@ -76,7 +76,7 @@ class IntegerInclusiveInterval {
}
};
-namespace IntegerIntervalUtils {
+namespace IntegerInclusiveIntervalUtils {
/// A list of integer intervals.
using IntervalList = SmallVector<IntegerInclusiveInterval, 8>;
@@ -108,7 +108,7 @@ void printIntervals(raw_ostream &OS,
IntervalList
mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);
-} // end namespace IntegerIntervalUtils
+} // end namespace IntegerInclusiveIntervalUtils
} // end namespace llvm
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 646e212b0ee04..cd51369c50b84 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -62,7 +62,7 @@ static cl::opt<std::string> OptBisectIntervals(
return;
}
- auto Intervals = IntegerIntervalUtils::parseIntervals(IntervalStr);
+ auto Intervals = IntegerInclusiveIntervalUtils::parseIntervals(IntervalStr);
if (!Intervals) {
handleAllErrors(Intervals.takeError(), [&](const StringError &E) {
errs() << "Error: Invalid interval specification for -opt-bisect: "
@@ -109,7 +109,7 @@ bool OptBisect::shouldRunPass(StringRef PassName,
// Check if current pass number falls within any of the specified intervals.
bool ShouldRun =
- IntegerIntervalUtils::contains(BisectIntervals, CurBisectNum);
+ IntegerInclusiveIntervalUtils::contains(BisectIntervals, CurBisectNum);
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index e81f683dc523c..ae388474a7925 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -12,7 +12,7 @@ namespace llvm {
void DebugCounter::printChunks(raw_ostream &OS,
ArrayRef<IntegerInclusiveInterval> Chunks) {
- IntegerIntervalUtils::printIntervals(OS, Chunks, ':');
+ IntegerInclusiveIntervalUtils::printIntervals(OS, Chunks, ':');
}
} // namespace llvm
@@ -134,7 +134,7 @@ void DebugCounter::push_back(const std::string &Val) {
}
auto ExpectedChunks =
- IntegerIntervalUtils::parseIntervals(CounterPair.second, ':');
+ IntegerInclusiveIntervalUtils::parseIntervals(CounterPair.second, ':');
if (!ExpectedChunks) {
handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
errs() << "DebugCounter Error: " << E.getMessage() << "\n";
diff --git a/llvm/lib/Support/IntegerInclusiveInterval.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
index 70c7809d06b73..06abf590926bf 100644
--- a/llvm/lib/Support/IntegerInclusiveInterval.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -1,11 +1,15 @@
-//===- llvm/Support/IntegerInclusiveInterval.cpp - Integer inclusive interval
-// parsing utility -----------*- C++ -*-===//
+//===- IntegerInclusiveInterval.cpp -----------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
+//
+// This file implements utilities for handling lists of inclusive integer intervals,
+// such as parsing interval strings like "1-10,20-30,45", which are used in debugging and bisection tools.
+//
+//===----------------------------------------------------------------------===//
#include "llvm/Support/IntegerInclusiveInterval.h"
#include "llvm/ADT/StringExtras.h"
@@ -16,8 +20,7 @@
using namespace llvm;
-namespace llvm {
-namespace IntegerIntervalUtils {
+namespace llvm::IntegerInclusiveIntervalUtils {
Expected<IntervalList> parseIntervals(StringRef Str, char Separator) {
IntervalList Intervals;
@@ -118,6 +121,4 @@ mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals) {
return Result;
}
-} // end namespace IntegerIntervalUtils
-
-} // end namespace llvm
+} // end namespace llvm::IntegerInclusiveIntervalUtils
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index 8b386ab646cf5..e0e8ae5259c16 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -26,13 +26,13 @@ static cl::opt<bool> Pessimist("pessimist", cl::init(false));
namespace {
bool isStillInteresting(ArrayRef<IntegerInclusiveInterval> Chunks) {
- IntegerIntervalUtils::IntervalList SimpleChunks =
- IntegerIntervalUtils::mergeAdjacentIntervals(Chunks);
+ IntegerInclusiveIntervalUtils::IntervalList SimpleChunks =
+ IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Chunks);
std::string ChunkStr;
{
raw_string_ostream OS(ChunkStr);
- IntegerIntervalUtils::printIntervals(OS, SimpleChunks);
+ IntegerInclusiveIntervalUtils::printIntervals(OS, SimpleChunks);
}
errs() << "Checking with: " << ChunkStr << "\n";
@@ -59,9 +59,9 @@ bool isStillInteresting(ArrayRef<IntegerInclusiveInterval> Chunks) {
return Res;
}
-bool increaseGranularity(IntegerIntervalUtils::IntervalList &Chunks) {
+bool increaseGranularity(IntegerInclusiveIntervalUtils::IntervalList &Chunks) {
errs() << "Increasing granularity\n";
- IntegerIntervalUtils::IntervalList NewChunks;
+ IntegerInclusiveIntervalUtils::IntervalList NewChunks;
bool SplitOne = false;
for (auto &C : Chunks) {
@@ -85,14 +85,14 @@ bool increaseGranularity(IntegerIntervalUtils::IntervalList &Chunks) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
- auto ExpectedChunks = IntegerIntervalUtils::parseIntervals(StartChunks, ',');
+ auto ExpectedChunks = IntegerInclusiveIntervalUtils::parseIntervals(StartChunks, ',');
if (!ExpectedChunks) {
handleAllErrors(ExpectedChunks.takeError(), [](const StringError &E) {
errs() << "Error parsing chunks: " << E.getMessage() << "\n";
});
return 1;
}
- IntegerIntervalUtils::IntervalList CurrChunks = std::move(*ExpectedChunks);
+ IntegerInclusiveIntervalUtils::IntervalList CurrChunks = std::move(*ExpectedChunks);
auto Program = sys::findProgramByName(ReproductionCmd);
if (!Program) {
@@ -132,7 +132,7 @@ int main(int argc, char **argv) {
}
errs() << "Minimal Chunks = ";
- IntegerIntervalUtils::printIntervals(
- llvm::errs(), IntegerIntervalUtils::mergeAdjacentIntervals(CurrChunks));
+ IntegerInclusiveIntervalUtils::printIntervals(
+ llvm::errs(), IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(CurrChunks));
errs() << "\n";
}
diff --git a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
index 36c439d1be716..9e80dc8242a4f 100644
--- a/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
+++ b/llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp
@@ -1,5 +1,4 @@
-//===- llvm/unittests/Support/IntegerInclusiveIntervalTest.cpp - Integer
-// inclusive interval tests ----------------===//
+//===- llvm/unittest/Support/IntegerInclusiveIntervalTest.cpp -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -47,8 +46,8 @@ TEST(IntegerInclusiveIntervalTest, IntervalOverlaps) {
EXPECT_FALSE(I3.overlaps(I4));
}
-TEST(IntegerIntervalUtilsTest, ParseSingleNumber) {
- auto ER = IntegerIntervalUtils::parseIntervals("42");
+TEST(IntegerInclusiveIntervalUtilsTest, ParseSingleNumber) {
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("42");
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
EXPECT_EQ(Intervals.size(), 1U);
@@ -56,8 +55,8 @@ TEST(IntegerIntervalUtilsTest, ParseSingleNumber) {
EXPECT_EQ(Intervals[0].getEnd(), 42);
}
-TEST(IntegerIntervalUtilsTest, ParseSingleInterval) {
- auto ER = IntegerIntervalUtils::parseIntervals("10-20");
+TEST(IntegerInclusiveIntervalUtilsTest, ParseSingleInterval) {
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("10-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
EXPECT_EQ(Intervals.size(), 1U);
@@ -65,8 +64,8 @@ TEST(IntegerIntervalUtilsTest, ParseSingleInterval) {
EXPECT_EQ(Intervals[0].getEnd(), 20);
}
-TEST(IntegerIntervalUtilsTest, ParseMultipleIntervals) {
- auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
+TEST(IntegerInclusiveIntervalUtilsTest, ParseMultipleIntervals) {
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("1-5,10,15-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
EXPECT_EQ(Intervals.size(), 3U);
@@ -80,8 +79,8 @@ TEST(IntegerIntervalUtilsTest, ParseMultipleIntervals) {
EXPECT_EQ(Intervals[2].getEnd(), 20);
}
-TEST(IntegerIntervalUtilsTest, ParseColonSeparatedIntervals) {
- auto ER = IntegerIntervalUtils::parseIntervals("1-5:10:15-20", ':');
+TEST(IntegerInclusiveIntervalUtilsTest, ParseColonSeparatedIntervals) {
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("1-5:10:15-20", ':');
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
EXPECT_EQ(Intervals.size(), 3U);
@@ -93,63 +92,63 @@ TEST(IntegerIntervalUtilsTest, ParseColonSeparatedIntervals) {
EXPECT_EQ(Intervals[2].getEnd(), 20);
}
-TEST(IntegerIntervalUtilsTest, ParseEmptyString) {
- auto ER = IntegerIntervalUtils::parseIntervals("");
+TEST(IntegerInclusiveIntervalUtilsTest, ParseEmptyString) {
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("");
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
EXPECT_TRUE(Intervals.empty());
}
-TEST(IntegerIntervalUtilsTest, ParseInvalidIntervals) {
+TEST(IntegerInclusiveIntervalUtilsTest, ParseInvalidIntervals) {
// Invalid number.
- auto ER1 = IntegerIntervalUtils::parseIntervals("abc");
+ auto ER1 = IntegerInclusiveIntervalUtils::parseIntervals("abc");
EXPECT_THAT_EXPECTED(ER1, Failed());
consumeError(ER1.takeError());
// Invalid interval (begin > end).
- auto ER2 = IntegerIntervalUtils::parseIntervals("10-5");
+ auto ER2 = IntegerInclusiveIntervalUtils::parseIntervals("10-5");
EXPECT_THAT_EXPECTED(ER2, Failed());
consumeError(ER2.takeError());
// Out of order intervals (DebugCounter constraint and overlap).
- auto ER3 = IntegerIntervalUtils::parseIntervals("10,5");
+ auto ER3 = IntegerInclusiveIntervalUtils::parseIntervals("10,5");
EXPECT_THAT_EXPECTED(ER3, Failed());
consumeError(ER3.takeError());
- auto ER4 = IntegerIntervalUtils::parseIntervals("1-5,3-7");
+ auto ER4 = IntegerInclusiveIntervalUtils::parseIntervals("1-5,3-7");
EXPECT_THAT_EXPECTED(ER4, Failed());
consumeError(ER4.takeError());
}
-TEST(IntegerIntervalUtilsTest, Contains) {
- auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
+TEST(IntegerInclusiveIntervalUtilsTest, Contains) {
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("1-5,10,15-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 1));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 3));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 5));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 10));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 15));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 18));
- EXPECT_TRUE(IntegerIntervalUtils::contains(Intervals, 20));
-
- EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 6));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 9));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 11));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 14));
- EXPECT_FALSE(IntegerIntervalUtils::contains(Intervals, 21));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 1));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 3));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 5));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 10));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 15));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 18));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(Intervals, 20));
+
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(Intervals, 6));
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(Intervals, 9));
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(Intervals, 11));
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(Intervals, 14));
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(Intervals, 21));
}
-TEST(IntegerIntervalUtilsTest, SeparatorParameter) {
- IntegerIntervalUtils::IntervalList ColonIntervals, CommaIntervals;
+TEST(IntegerInclusiveIntervalUtilsTest, SeparatorParameter) {
+ IntegerInclusiveIntervalUtils::IntervalList ColonIntervals, CommaIntervals;
// Test explicit separator parameters.
- auto ERC = IntegerIntervalUtils::parseIntervals("1-5:10:15-20", ':');
+ auto ERC = IntegerInclusiveIntervalUtils::parseIntervals("1-5:10:15-20", ':');
ASSERT_THAT_EXPECTED(ERC, Succeeded());
ColonIntervals = std::move(*ERC);
- auto ERM = IntegerIntervalUtils::parseIntervals("1-5,10,15-20", ',');
+ auto ERM = IntegerInclusiveIntervalUtils::parseIntervals("1-5,10,15-20", ',');
ASSERT_THAT_EXPECTED(ERM, Succeeded());
CommaIntervals = std::move(*ERM);
@@ -160,20 +159,20 @@ TEST(IntegerIntervalUtilsTest, SeparatorParameter) {
}
// Test that both work with contains().
- EXPECT_TRUE(IntegerIntervalUtils::contains(ColonIntervals, 3));
- EXPECT_TRUE(IntegerIntervalUtils::contains(CommaIntervals, 3));
- EXPECT_TRUE(IntegerIntervalUtils::contains(ColonIntervals, 10));
- EXPECT_TRUE(IntegerIntervalUtils::contains(CommaIntervals, 10));
- EXPECT_TRUE(IntegerIntervalUtils::contains(ColonIntervals, 18));
- EXPECT_TRUE(IntegerIntervalUtils::contains(CommaIntervals, 18));
-
- EXPECT_FALSE(IntegerIntervalUtils::contains(ColonIntervals, 8));
- EXPECT_FALSE(IntegerIntervalUtils::contains(CommaIntervals, 8));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(ColonIntervals, 3));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(CommaIntervals, 3));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(ColonIntervals, 10));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(CommaIntervals, 10));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(ColonIntervals, 18));
+ EXPECT_TRUE(IntegerInclusiveIntervalUtils::contains(CommaIntervals, 18));
+
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(ColonIntervals, 8));
+ EXPECT_FALSE(IntegerInclusiveIntervalUtils::contains(CommaIntervals, 8));
}
-TEST(IntegerIntervalUtilsTest, DefaultCommaSeparator) {
+TEST(IntegerInclusiveIntervalUtilsTest, DefaultCommaSeparator) {
// Test that comma is the default separator.
- auto ER = IntegerIntervalUtils::parseIntervals("1-5,10,15-20");
+ auto ER = IntegerInclusiveIntervalUtils::parseIntervals("1-5,10,15-20");
ASSERT_THAT_EXPECTED(ER, Succeeded());
auto Intervals = std::move(*ER);
EXPECT_EQ(Intervals.size(), 3U);
@@ -186,16 +185,16 @@ TEST(IntegerIntervalUtilsTest, DefaultCommaSeparator) {
}
TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
- IntegerIntervalUtils::IntervalList Input, Expected, Result;
+ IntegerInclusiveIntervalUtils::IntervalList Input, Expected, Result;
// Empty input
- Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ Result = IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_TRUE(Result.empty());
// Single interval - no change.
Input.push_back(IntegerInclusiveInterval(5, 10));
Expected.push_back(IntegerInclusiveInterval(5, 10));
- Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ Result = IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
// Adjacent intervals should merge.
@@ -205,7 +204,7 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Input.push_back(IntegerInclusiveInterval(4, 6));
Input.push_back(IntegerInclusiveInterval(7, 9));
Expected.push_back(IntegerInclusiveInterval(1, 9));
- Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ Result = IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
// Non-adjacent intervals should not merge.
@@ -217,7 +216,7 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Expected.push_back(IntegerInclusiveInterval(1, 3));
Expected.push_back(IntegerInclusiveInterval(5, 7));
Expected.push_back(IntegerInclusiveInterval(10, 12));
- Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ Result = IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
// Mixed adjacent and non-adjacent intervals.
@@ -231,7 +230,7 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Expected.push_back(IntegerInclusiveInterval(1, 6)); // Merged 1-3 and 4-6.
Expected.push_back(
IntegerInclusiveInterval(8, 16)); // Merged 8-10, 11-13, 14-16.
- Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ Result = IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
// Single numbers that are adjacent.
@@ -241,6 +240,6 @@ TEST(IntegerInclusiveIntervalTest, MergeAdjacentIntervals) {
Input.push_back(IntegerInclusiveInterval(6));
Input.push_back(IntegerInclusiveInterval(7));
Expected.push_back(IntegerInclusiveInterval(5, 7));
- Result = IntegerIntervalUtils::mergeAdjacentIntervals(Input);
+ Result = IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(Input);
EXPECT_EQ(Expected, Result);
}
>From 4ce9ab2f99a7d422c424bbe79cdeaad1a88b4e1c Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Tue, 30 Dec 2025 17:42:46 +0000
Subject: [PATCH 49/49] format
---
llvm/include/llvm/Support/DebugCounter.h | 4 ++--
llvm/lib/IR/OptBisect.cpp | 3 ++-
llvm/lib/Support/IntegerInclusiveInterval.cpp | 5 +++--
llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp | 9 ++++++---
4 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index ce22f65eb29b6..7e83fc8ff8767 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -85,8 +85,8 @@ class DebugCounter {
/// Return true on parsing error and print the error message on the
/// llvm::errs()
- LLVM_ABI static bool parseChunks(StringRef Str,
- IntegerInclusiveIntervalUtils::IntervalList &Res);
+ LLVM_ABI static bool
+ parseChunks(StringRef Str, IntegerInclusiveIntervalUtils::IntervalList &Res);
/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index cd51369c50b84..bb9fba66ddf95 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -62,7 +62,8 @@ static cl::opt<std::string> OptBisectIntervals(
return;
}
- auto Intervals = IntegerInclusiveIntervalUtils::parseIntervals(IntervalStr);
+ auto Intervals =
+ IntegerInclusiveIntervalUtils::parseIntervals(IntervalStr);
if (!Intervals) {
handleAllErrors(Intervals.takeError(), [&](const StringError &E) {
errs() << "Error: Invalid interval specification for -opt-bisect: "
diff --git a/llvm/lib/Support/IntegerInclusiveInterval.cpp b/llvm/lib/Support/IntegerInclusiveInterval.cpp
index 06abf590926bf..c38e32b8a5ed2 100644
--- a/llvm/lib/Support/IntegerInclusiveInterval.cpp
+++ b/llvm/lib/Support/IntegerInclusiveInterval.cpp
@@ -6,8 +6,9 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements utilities for handling lists of inclusive integer intervals,
-// such as parsing interval strings like "1-10,20-30,45", which are used in debugging and bisection tools.
+// This file implements utilities for handling lists of inclusive integer
+// intervals, such as parsing interval strings like "1-10,20-30,45", which are
+// used in debugging and bisection tools.
//
//===----------------------------------------------------------------------===//
diff --git a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
index e0e8ae5259c16..eaf173d4a88a2 100644
--- a/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
+++ b/llvm/tools/reduce-chunk-list/reduce-chunk-list.cpp
@@ -85,14 +85,16 @@ bool increaseGranularity(IntegerInclusiveIntervalUtils::IntervalList &Chunks) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
- auto ExpectedChunks = IntegerInclusiveIntervalUtils::parseIntervals(StartChunks, ',');
+ auto ExpectedChunks =
+ IntegerInclusiveIntervalUtils::parseIntervals(StartChunks, ',');
if (!ExpectedChunks) {
handleAllErrors(ExpectedChunks.takeError(), [](const StringError &E) {
errs() << "Error parsing chunks: " << E.getMessage() << "\n";
});
return 1;
}
- IntegerInclusiveIntervalUtils::IntervalList CurrChunks = std::move(*ExpectedChunks);
+ IntegerInclusiveIntervalUtils::IntervalList CurrChunks =
+ std::move(*ExpectedChunks);
auto Program = sys::findProgramByName(ReproductionCmd);
if (!Program) {
@@ -133,6 +135,7 @@ int main(int argc, char **argv) {
errs() << "Minimal Chunks = ";
IntegerInclusiveIntervalUtils::printIntervals(
- llvm::errs(), IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(CurrChunks));
+ llvm::errs(),
+ IntegerInclusiveIntervalUtils::mergeAdjacentIntervals(CurrChunks));
errs() << "\n";
}
More information about the llvm-commits
mailing list