[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
Fri Sep 5 13:55:46 PDT 2025
https://github.com/YonahGoldberg updated https://github.com/llvm/llvm-project/pull/152393
>From 329098d16054afc1975327e75ebf02fb0ebe37a5 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/31] 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 d813ae933d65e..7b244c833f767 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 723514de5f46c562591fdf634442866498673969 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/31] 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 7b244c833f767..ee787e0580032 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 431c13be5ad020febf1fc2e51dd3af5f8384127f 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/31] 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 ee787e0580032..9dcc0077552d4 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 ec6842e2c65af9260284850d17dde4b7c3cf3bf8 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/31] 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 6b3ed997ddea73cdfdd3a2dc7ad8e225d27363fd 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/31] 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 9dcc0077552d4..bc2294a870389 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 895a1bbba27fac2187bbdd7f251fff800d3883aa 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/31] 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 4b382092d7b7dd2ccf9b02e476a69477bf80d869 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/31] range support
---
llvm/include/llvm/IR/OptBisect.h | 40 +--
llvm/include/llvm/Support/DebugCounter.h | 17 +-
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, 629 insertions(+), 149 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 bc2294a870389..901fb5625aefd 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 {
virtual ~OptBisect() = 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 89349d1ebffee..d6f46ce2346d8 100644
--- a/llvm/include/llvm/Support/DebugCounter.h
+++ b/llvm/include/llvm/Support/DebugCounter.h
@@ -48,6 +48,7 @@
#include "llvm/ADT/UniqueVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Range.h"
#include <string>
namespace llvm {
@@ -56,18 +57,10 @@ 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; }
- };
-
- LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<Chunk>);
+ // For backward compatibility, alias Range as Chunk
+ using Chunk = Range;
- /// 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 void printChunks(raw_ostream &OS, ArrayRef<Range> Ranges);
/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
@@ -176,7 +169,7 @@ class DebugCounter {
uint64_t CurrChunkIdx = 0;
bool IsSet = false;
std::string Desc;
- SmallVector<Chunk> Chunks;
+ SmallVector<Range> Chunks;
};
DenseMap<unsigned, 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 10b6101d73277..f6c64579cec5c 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -231,6 +231,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 6b65720440f30..ce01400893724 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -9,77 +9,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
@@ -185,11 +116,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());
unsigned CounterID = getCounterId(std::string(CounterName));
if (!CounterID) {
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 868c40b13b9b2..e1821b0172960 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -74,6 +74,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 d3f5add03c73de80b56a4bc8262d5b8a6273f000 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/31] 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 901fb5625aefd..680f4469402af 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 ce01400893724..fed7b0154c3de 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -119,7 +119,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 6f20867970219fea1b496ede854b0c6b3577f07b 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/31] 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 5f8719360af8521b6d29782aa0e182e0eb2da0f3 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/31] 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 680f4469402af..1963601b95be9 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 8ab62b35ec7ab12cf3204f40b2e34ebb22d5a19a 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/31] cleanup
---
llvm/include/llvm/Support/DebugCounter.h | 5 +----
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, 23 insertions(+), 31 deletions(-)
diff --git a/llvm/include/llvm/Support/DebugCounter.h b/llvm/include/llvm/Support/DebugCounter.h
index d6f46ce2346d8..f51a881ac4e24 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;
-
LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<Range> Ranges);
/// Returns a reference to the singleton instance.
@@ -169,7 +166,7 @@ class DebugCounter {
uint64_t CurrChunkIdx = 0;
bool IsSet = false;
std::string Desc;
- SmallVector<Range> Chunks;
+ RangeUtils::RangeList Chunks;
};
DenseMap<unsigned, 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 fed7b0154c3de..a704119a38426 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -116,13 +116,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());
unsigned CounterID = getCounterId(std::string(CounterName));
if (!CounterID) {
@@ -134,7 +127,8 @@ void DebugCounter::push_back(const std::string &Val) {
CounterInfo &Counter = Counters[CounterID];
Counter.IsSet = true;
- Counter.Chunks = std::move(Chunks);
+ if (!RangeUtils::parseRanges(CounterPair.second, Counter.Chunks, ':'))
+ return;
}
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 c3e5c7dc1bc66cb18e106654d12c16f70dbaa431 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/31] 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 1963601b95be9..fe2f808077ab4 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 4cf5a990459ca913d347a5570fc540f341d1712a 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/31] 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 | 12 ++-
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, 145 insertions(+), 54 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index fe2f808077ab4..9e3400325defd 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 a704119a38426..4ac292a6c15fb 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -117,6 +117,15 @@ void DebugCounter::push_back(const std::string &Val) {
}
StringRef CounterName = CounterPair.first;
+ auto ExpectedChunks = RangeUtils::parseRanges(CounterPair.second, ':');
+ if (!ExpectedChunks) {
+ handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
+ errs() << "DebugCounter Error: " << E.getMessage() << "\n";
+ });
+ return;
+ }
+ RangeUtils::RangeList Chunks = std::move(*ExpectedChunks);
+
unsigned CounterID = getCounterId(std::string(CounterName));
if (!CounterID) {
errs() << "DebugCounter Error: " << CounterName
@@ -127,8 +136,7 @@ void DebugCounter::push_back(const std::string &Val) {
CounterInfo &Counter = Counters[CounterID];
Counter.IsSet = true;
- if (!RangeUtils::parseRanges(CounterPair.second, Counter.Chunks, ':'))
- return;
+ 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 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 0eefd68066f8e071c58992f85d21a60c990c4b9f 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/31] 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 a1595382b68df774197075c69fe52e25c9975fc0 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/31] 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 4ac292a6c15fb..3b35a84a94253 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -122,7 +122,7 @@ void DebugCounter::push_back(const std::string &Val) {
handleAllErrors(ExpectedChunks.takeError(), [&](const StringError &E) {
errs() << "DebugCounter Error: " << E.getMessage() << "\n";
});
- return;
+ exit(1);
}
RangeUtils::RangeList Chunks = std::move(*ExpectedChunks);
>From 3215304e6ba90c30cc9ae99e47aafd34688424de 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/31] fix error handling tests
---
llvm/lib/Support/DebugCounter.cpp | 4 +--
llvm/test/Other/debugcounter-multi-ranges.ll | 38 ++++++++++++++++----
2 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 3b35a84a94253..7e65a3efa18ce 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -113,7 +113,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;
@@ -130,7 +130,7 @@ void DebugCounter::push_back(const std::string &Val) {
if (!CounterID) {
errs() << "DebugCounter Error: " << CounterName
<< " is not a registered counter\n";
- return;
+ exit(1);
}
enableAllCounters();
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 af7873f55de04dc8b8761b55e81d27fad8e04520 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/31] 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 c27ce560333596aa5e0ba262e7e6386027034fbf 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/31] 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 6c4fea1e3584131058b388f62f1e85f535028cb3 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/31] 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 5e1d4431a6bf46ab08e662a45d8a6b15c60eaf91 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/31] 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 466991dcd876e4ebfda3eaf031ac714387f74642 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/31] 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 0eaab13d5a4666afb507320fff509ad5226560da 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/31] 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 5ce4228cc68d8c2b08c449e9607dafc8501d01cb 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/31] 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 095c35884e50af4ffc06e36869e8b6b1dc72271c 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/31] 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 dce302aabcb1cfcfe34dc4e2540b98b8c6fb98c7 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/31] 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 2b779d3cb4a77ef85372497f8d44199a5b840279 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/31] 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 5a80bfb990f6595040efed5aa4c74089360a0380 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/31] 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 3616aa638bf60f5e5051929865cee1e546af7c39 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/31] 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 9e3400325defd..de008338209a5 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 7e65a3efa18ce..1abf4f872f03d 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -10,7 +10,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 58825847840c71b9821e2e3cbe45a261345c9b25 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/31] 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 0f0499c4a5ad2c9febba20cc258518b0b42a47e1 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/31] 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 1615205b571fc53f500cdafdc3290a7714a7b157 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/31] 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;
More information about the llvm-commits
mailing list