Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c64c082
opt bisect skip
YonahGoldberg Aug 6, 2025
57b3806
format
YonahGoldberg Aug 6, 2025
eb1d01b
comment
YonahGoldberg Aug 6, 2025
2500d20
newline
YonahGoldberg Aug 6, 2025
a5e1334
renaming
YonahGoldberg Aug 20, 2025
49f8862
format
YonahGoldberg Aug 20, 2025
0242e6f
range support
YonahGoldberg Sep 3, 2025
d6c79ca
small changes
YonahGoldberg Sep 3, 2025
607aa7d
remove opt-disable-indices
YonahGoldberg Sep 3, 2025
502f657
remove
YonahGoldberg Sep 3, 2025
31041f3
cleanup
YonahGoldberg Sep 3, 2025
abef143
format
YonahGoldberg Sep 3, 2025
7940281
use Expect for Range
YonahGoldberg Sep 3, 2025
c692516
format
YonahGoldberg Sep 3, 2025
d5b2fb9
fix hang
YonahGoldberg Sep 3, 2025
eda95bf
fix error handling tests
YonahGoldberg Sep 3, 2025
dbe0f8c
format
YonahGoldberg Sep 4, 2025
a8c0f6a
cleanup
YonahGoldberg Sep 4, 2025
6e90313
clang format
YonahGoldberg Sep 4, 2025
28d8f29
fix minor formatting bug
YonahGoldberg Sep 4, 2025
5fdf15f
small bug
YonahGoldberg Sep 4, 2025
9c88bf8
format
YonahGoldberg Sep 4, 2025
a64d3d3
allow -opt-bisect=0 and -opt-bisect=-1
YonahGoldberg Sep 4, 2025
8050943
comment change
YonahGoldberg Sep 4, 2025
f975b6a
format
YonahGoldberg Sep 4, 2025
c2bc508
cleanup
YonahGoldberg Sep 5, 2025
3c10d16
format
YonahGoldberg Sep 5, 2025
9940557
more cleanup
YonahGoldberg Sep 5, 2025
82fbca2
format
YonahGoldberg Sep 5, 2025
746b560
range test cleanup
YonahGoldberg Sep 5, 2025
5e9cf0d
format
YonahGoldberg Sep 5, 2025
a4b5998
move range from struct -> class
YonahGoldberg Sep 5, 2025
f8ee576
better range size function
YonahGoldberg Sep 5, 2025
b844219
range size checks
YonahGoldberg Sep 5, 2025
a23b843
format
YonahGoldberg Sep 5, 2025
f77b300
format
YonahGoldberg Sep 5, 2025
352cdfd
use list separator
YonahGoldberg Sep 22, 2025
95eb8d8
remove size
YonahGoldberg Sep 23, 2025
7d38a2d
redundant include
YonahGoldberg Sep 23, 2025
376b272
IntegerInclusiveInterval
YonahGoldberg Sep 23, 2025
1dde98f
format
YonahGoldberg Sep 23, 2025
c02b956
more pruning range
YonahGoldberg Sep 23, 2025
4faf429
format
YonahGoldberg Sep 23, 2025
23766b7
format
YonahGoldberg Sep 23, 2025
05efe9a
fix tests
YonahGoldberg Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions llvm/include/llvm/IR/OptBisect.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
#include <limits>
#include "llvm/Support/IntegerInclusiveInterval.h"

namespace llvm {

Expand All @@ -40,7 +40,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:
Expand All @@ -53,12 +53,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 intervals to determine if the specified pass should run.
///
/// The method prints the name of the pass, its assigned bisect number, and
/// whether or not the pass will be executed. It returns true if the pass
/// should run, i.e. if the bisect limit is set to -1 or has not yet been
/// exceeded.
/// should run, i.e. if no intervals are specified or the current pass number
/// falls within one of the specified intervals.
///
/// Most passes should not call this routine directly. Instead, it is called
/// through helper routines provided by the base classes of the pass. For
Expand All @@ -67,20 +67,22 @@ 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 !BisectIntervals.empty(); }

/// Set the new optimization limit and reset the counter. Passing
/// OptBisect::Disabled disables the limiting.
void setLimit(int Limit) {
BisectLimit = Limit;
LastBisectNum = 0;
/// Set intervals directly from an IntervalList.
void setIntervals(IntegerIntervalUtils::IntervalList Intervals) {
BisectIntervals = std::move(Intervals);
}

static constexpr int Disabled = std::numeric_limits<int>::max();
/// Clear all intervals, effectively disabling bisection.
void clearIntervals() {
BisectIntervals.clear();
LastBisectNum = 0;
}

private:
int BisectLimit = Disabled;
mutable int LastBisectNum = 0;
IntegerIntervalUtils::IntervalList BisectIntervals;
};

/// This class implements a mechanism to disable passes and individual
Expand Down
19 changes: 5 additions & 14 deletions llvm/include/llvm/Support/DebugCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/// debug. That is where debug counting steps in. You can instrument the pass
/// with a debug counter before it does a certain thing, and depending on the
/// counts, it will either execute that thing or not. The debug counter itself
/// consists of a list of chunks (inclusive numeric ranges). `shouldExecute`
/// consists of a list of chunks (inclusive numeric intervals). `shouldExecute`
/// returns true iff the list is empty or the current count is in one of the
/// chunks.
///
Expand Down Expand Up @@ -48,6 +48,7 @@
#include "llvm/ADT/UniqueVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/IntegerInclusiveInterval.h"
#include <string>

namespace llvm {
Expand All @@ -56,18 +57,8 @@ class raw_ostream;

class DebugCounter {
public:
struct Chunk {
int64_t Begin;
int64_t End;
LLVM_ABI void print(llvm::raw_ostream &OS);
bool contains(int64_t Idx) const { return Idx >= Begin && Idx <= End; }
};

LLVM_ABI static void printChunks(raw_ostream &OS, ArrayRef<Chunk>);

/// 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<IntegerInclusiveInterval> Intervals);

/// Returns a reference to the singleton instance.
LLVM_ABI static DebugCounter &instance();
Expand Down Expand Up @@ -176,7 +167,7 @@ class DebugCounter {
uint64_t CurrChunkIdx = 0;
bool IsSet = false;
std::string Desc;
SmallVector<Chunk> Chunks;
IntegerIntervalUtils::IntervalList Chunks;
};

DenseMap<unsigned, CounterInfo> Counters;
Expand Down
115 changes: 115 additions & 0 deletions llvm/include/llvm/Support/IntegerInclusiveInterval.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//===- llvm/Support/IntegerInclusiveInterval.h - Integer inclusive interval
// parsing utility -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides utilities for parsing interval specifications like
// "1-10,20-30,45" which are commonly used in debugging and bisection tools,
// but the same utilities can be used for any other type of interval.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_INTEGER_INCLUSIVE_INTERVAL_H
#define LLVM_SUPPORT_INTEGER_INCLUSIVE_INTERVAL_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <cassert>
#include <cstdint>

namespace llvm {
class raw_ostream;
} // end namespace llvm

namespace llvm {

/// Represents an inclusive integer interval [Begin, End] where Begin <= End.
class IntegerInclusiveInterval {
int64_t Begin;
int64_t End;

public:
/// Create an interval [Begin, End].
IntegerInclusiveInterval(int64_t Begin, int64_t End)
: Begin(Begin), End(End) {
assert(Begin <= End && "Interval Begin must be <= End");
}
/// Create a singleton interval [Single, Single].
IntegerInclusiveInterval(int64_t Single) : Begin(Single), End(Single) {}

int64_t getBegin() const { return Begin; }
int64_t getEnd() const { return End; }

void setBegin(int64_t NewBegin) {
assert(NewBegin <= End && "Interval Begin must be <= End");
Begin = NewBegin;
}
void setEnd(int64_t NewEnd) {
assert(Begin <= NewEnd && "Interval Begin must be <= End");
End = NewEnd;
}

/// Check if the given value is within this interval (inclusive).
bool contains(int64_t Value) const { return Value >= Begin && Value <= End; }

/// Check if this interval overlaps with another interval.
bool overlaps(const IntegerInclusiveInterval &Other) const {
return Begin <= Other.End && End >= Other.Begin;
}

/// Print the interval to the output stream.
void print(raw_ostream &OS) const {
if (Begin == End)
OS << Begin;
else
OS << Begin << "-" << End;
}

bool operator==(const IntegerInclusiveInterval &Other) const {
return Begin == Other.Begin && End == Other.End;
}
};

namespace IntegerIntervalUtils {

/// A list of integer intervals.
using IntervalList = SmallVector<IntegerInclusiveInterval, 8>;

/// Parse a interval specification string like "1-10,20-30,45" or
/// "1-10:20-30:45". Intervals must be in increasing order and non-overlapping.
/// \param IntervalStr The string to parse.
/// \param Separator The separator character to use (',' or ':').
/// \returns Expected<IntervalList> containing the parsed intervals on success,
/// or an Error on failure.
Expected<IntervalList> parseIntervals(StringRef IntervalStr,
char Separator = ',');

/// Check if a value is contained in any of the intervals.
bool contains(ArrayRef<IntegerInclusiveInterval> Intervals, int64_t Value);

/// Print intervals to output stream.
/// \param OS The output stream to print to.
/// \param Intervals The intervals to print.
/// \param Separator The separator character to use between intervals (i.e. ','
/// or
/// ':').
void printIntervals(raw_ostream &OS,
ArrayRef<IntegerInclusiveInterval> Intervals,
char Separator = ',');

/// Merge adjacent/consecutive intervals into single intervals.
/// Example: [1-3, 4-6, 8-10] -> [1-6, 8-10].
IntervalList
mergeAdjacentIntervals(ArrayRef<IntegerInclusiveInterval> Intervals);

} // end namespace IntegerIntervalUtils

} // end namespace llvm

#endif // LLVM_SUPPORT_INTEGER_INCLUSIVE_INTERVAL_H
58 changes: 51 additions & 7 deletions llvm/lib/IR/OptBisect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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/IntegerInclusiveInterval.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdlib>

using namespace llvm;

Expand All @@ -30,12 +33,49 @@ static OptDisable &getOptDisabler() {
return OptDisabler;
}

static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
cl::init(OptBisect::Disabled), cl::Optional,
cl::cb<void, int>([](int Limit) {
getOptBisector().setLimit(Limit);
}),
cl::desc("Maximum optimization to perform"));
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.
getOptBisector().setIntervals({{1, std::numeric_limits<int>::max()}});
else if (Limit == 0)
// 0 means run no passes.
getOptBisector().setIntervals({{0, 0}});
else if (Limit > 0)
// Convert limit to interval 1-Limit.
getOptBisector().setIntervals({{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)"));

static cl::opt<std::string> OptBisectIntervals(
"opt-bisect", cl::Hidden, cl::Optional,
cl::cb<void, const std::string &>([](const std::string &IntervalStr) {
if (IntervalStr == "-1") {
// -1 means run all passes.
getOptBisector().setIntervals({{1, std::numeric_limits<int>::max()}});
return;
}

auto Intervals = IntegerIntervalUtils::parseIntervals(IntervalStr);
if (!Intervals) {
handleAllErrors(Intervals.takeError(), [&](const StringError &E) {
errs() << "Error: Invalid interval specification for -opt-bisect: "
<< IntervalStr << " (" << E.getMessage() << ")\n";
});
exit(1);
}
getOptBisector().setIntervals(std::move(*Intervals));
}),
cl::desc("Run optimization passes only for the specified intervals. "
"Format: '1-10,20-30,45' runs passes 1-10, 20-30, and 45, where "
"index 1 is the first pass. Supply '0' to run no passes and -1 to "
"run all passes."));

static cl::opt<bool> OptBisectVerbose(
"opt-bisect-verbose",
Expand Down Expand Up @@ -66,7 +106,11 @@ bool OptBisect::shouldRunPass(StringRef PassName,
assert(isEnabled());

int CurBisectNum = ++LastBisectNum;
bool ShouldRun = (BisectLimit == -1 || CurBisectNum <= BisectLimit);

// Check if current pass number falls within any of the specified intervals.
bool ShouldRun =
IntegerIntervalUtils::contains(BisectIntervals, CurBisectNum);

if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
return ShouldRun;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ add_llvm_component_library(LLVMSupport
PluginLoader.cpp
PrettyStackTrace.cpp
RandomNumberGenerator.cpp
IntegerInclusiveInterval.cpp
Regex.cpp
RewriteBuffer.cpp
RewriteRope.cpp
Expand Down
Loading
Loading