-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[OptBisect] Add support for selecting ranges of passes and refactor DebugCounter to use a shared Range API. #152393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
329098d
723514d
431c13b
ec6842e
6b3ed99
895a1bb
4b38209
d3f5add
6f20867
5f87193
8ab62b3
c3e5c7d
4cf5a99
0eefd68
a159538
3215304
af7873f
c27ce56
6c4fea1
5e1d443
466991d
0eaab13
5ce4228
095c358
dce302a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,97 @@ | ||||||
//===- 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 "llvm/Support/Error.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(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(const 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; } | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should return an unsigned type? |
||||||
|
||||||
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; | ||||||
} | ||||||
}; | ||||||
|
||||||
/// Utility class for parsing and managing range specifications | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Here an elsewhere, end sentences with a period, including in doc comments. |
||||||
class RangeUtils { | ||||||
public: | ||||||
using RangeList = SmallVector<Range, 8>; | ||||||
|
||||||
/// Parse a range specification string like "1-10,20-30,45" or | ||||||
/// "1-10:20-30:45". Ranges must be in increasing order and non-overlapping. | ||||||
/// \param RangeStr The string to parse | ||||||
/// \param Separator The separator character to use (',' or ':') | ||||||
/// \returns Expected<RangeList> containing the parsed ranges on success, | ||||||
/// or an Error on failure | ||||||
static Expected<RangeList> parseRanges(const StringRef RangeStr, | ||||||
const char Separator = ','); | ||||||
|
||||||
/// Legacy interface for backward compatibility. | ||||||
/// \deprecated Use the Expected<RangeList> version instead | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a brand-new API, why have a deprecated interface? |
||||||
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 = ','); | ||||||
|
||||||
/// 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(const ArrayRef<Range> Ranges); | ||||||
}; | ||||||
|
||||||
} // end namespace llvm | ||||||
|
||||||
#endif // LLVM_SUPPORT_RANGE_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
||
|
@@ -30,12 +33,55 @@ 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().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); | ||
auto Ranges = RangeUtils::parseRanges(RangeStr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Going through a string and then parsing it here is redundant? You can directly create the range. |
||
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( | ||
"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 (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) { | ||
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, 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", | ||
|
@@ -66,7 +112,10 @@ 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 ranges | ||
bool ShouldRun = RangeUtils::contains(BisectRanges, CurBisectNum); | ||
|
||
if (OptBisectVerbose) | ||
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun); | ||
return ShouldRun; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and elsewhere, drop the const on non-reference/pointer params.