[llvm] [OptBisect] Add function filtering support to opt-bisect (PR #222123)
Daniel Donenfeld via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 07:17:15 PDT 2026
https://github.com/daniel-donenfeld updated https://github.com/llvm/llvm-project/pull/222123
>From d1fe09515c84b2558e8051a9e146a8be61371429 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Wed, 2 Sep 2026 19:36:25 +0000
Subject: [PATCH 1/5] Add two additional control to opt-bisect. The first
extends -opt-disable to accept pass-number intervals, including -1 to disable
all passes. The second restricts the behavior of opt-bisect to only the
functions passed to -opt-bisect-funcs. Added a lit test to check the verbose
output using the new flags.
---
llvm/include/llvm/IR/OptBisect.h | 40 ++++++-
llvm/lib/Analysis/LoopPass.cpp | 6 +-
llvm/lib/Analysis/RegionPass.cpp | 6 +-
llvm/lib/IR/OptBisect.cpp | 52 ++++++++-
llvm/lib/IR/Pass.cpp | 4 +-
llvm/lib/Passes/StandardInstrumentations.cpp | 6 +-
llvm/test/Other/opt-bisect-skip-and-filter.ll | 107 ++++++++++++++++++
7 files changed, 208 insertions(+), 13 deletions(-)
create mode 100644 llvm/test/Other/opt-bisect-skip-and-filter.ll
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 2cfb612020ae7..7198daf507dfd 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"
@@ -31,6 +32,11 @@ class OptPassGate {
/// over.
virtual bool shouldRunPass(StringRef PassName,
StringRef IRDescription) const {
+ return shouldRunPass(PassName, IRDescription, "");
+ }
+
+ virtual bool shouldRunPass(StringRef PassName, StringRef IRDescription,
+ StringRef FuncName) const {
return true;
}
@@ -68,17 +74,20 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// Most passes should not call this routine directly. Instead, it is called
/// through helper routines provided by the base classes of the pass. For
/// instance, function passes should call FunctionPass::skipFunction().
- bool shouldRunPass(StringRef PassName,
- StringRef IRDescription) const override;
+ bool shouldRunPass(StringRef PassName, StringRef IRDescription,
+ StringRef FuncName) const override;
/// isEnabled() should return true before calling shouldRunPass().
bool isEnabled() const override {
- return !BisectIntervals.empty() || !DisabledPasses.empty();
+ return !BisectIntervals.empty() || !DisabledPasses.empty() ||
+ !DisabledIntervals.empty();
}
void reset() override {
clearIntervals();
DisabledPasses.clear();
+ clearDisabledIntervals();
+ clearEnabledFuncs();
}
/// Set intervals directly from an IntervalList.
@@ -96,11 +105,36 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// to be disabled. Multiple pass names can be provided with comma separation.
void setDisabled(StringRef Pass) { DisabledPasses.insert(Pass); }
+ /// Set intervals directly from an IntervalList.
+ void
+ setDisabledIntervals(IntegerInclusiveIntervalUtils::IntervalList Intervals) {
+ DisabledIntervals.append(Intervals);
+ }
+
+ /// Clear all disabled intervals.
+ void clearDisabledIntervals() {
+ DisabledIntervals.clear();
+ LastDisableNum = 0;
+ }
+
+ /// Add a function name to the set of functions enabled for opt bisect.
+ void setEnabledFunc(StringRef FuncName) {
+ OptBisectFuncNames.insert(FuncName);
+ }
+
+ /// Clear the set of functions enabled for opt bisect, this reenables all
+ /// functions.
+ void clearEnabledFuncs() { OptBisectFuncNames.clear(); }
+
private:
mutable int LastBisectNum = 0;
IntegerInclusiveIntervalUtils::IntervalList BisectIntervals;
StringSet<> DisabledPasses = {};
+ IntegerInclusiveIntervalUtils::IntervalList DisabledIntervals;
+ mutable int LastDisableNum = 0;
+
+ StringSet<> OptBisectFuncNames = {};
};
/// Singleton instance of the OptPassGate class, so multiple pass managers don't
diff --git a/llvm/lib/Analysis/LoopPass.cpp b/llvm/lib/Analysis/LoopPass.cpp
index 85c15c5721cd6..4e5d0e4a03a0a 100644
--- a/llvm/lib/Analysis/LoopPass.cpp
+++ b/llvm/lib/Analysis/LoopPass.cpp
@@ -372,9 +372,13 @@ bool LoopPass::skipLoop(const Loop *L) const {
return false;
// Check the opt bisect limit.
const OptPassGate &Gate = F->getContext().getOptPassGate();
+
if (Gate.isEnabled() &&
- !Gate.shouldRunPass(this->getPassName(), getDescription(*L)))
+ !Gate.shouldRunPass(this->getPassName(), getDescription(*L),
+ F->getName())) {
return true;
+ }
+
// Check for the OptimizeNone attribute.
if (F->hasOptNone()) {
// FIXME: Report this to dbgs() only once per function.
diff --git a/llvm/lib/Analysis/RegionPass.cpp b/llvm/lib/Analysis/RegionPass.cpp
index ae1d84659de86..6ebd1ef2cf261 100644
--- a/llvm/lib/Analysis/RegionPass.cpp
+++ b/llvm/lib/Analysis/RegionPass.cpp
@@ -283,9 +283,11 @@ static std::string getDescription(const Region &R) {
bool RegionPass::skipRegion(Region &R) const {
Function &F = *R.getEntry()->getParent();
const OptPassGate &Gate = F.getContext().getOptPassGate();
- if (Gate.isEnabled() &&
- !Gate.shouldRunPass(this->getPassName(), getDescription(R)))
+
+ if (Gate.isEnabled() && !Gate.shouldRunPass(this->getPassName(),
+ getDescription(R), F.getName())) {
return true;
+ }
if (F.hasOptNone()) {
// Report this only once per function.
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 39562664e609c..3c44a411ff21c 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -79,13 +79,45 @@ static cl::opt<bool> OptBisectVerbose(
"Show verbose output when opt-bisect-limit and/or opt-disable are set"),
cl::Hidden, cl::init(true), cl::Optional);
+// Augment -opt-disable to support intervals in addition to pass names
static cl::list<std::string> OptDisablePasses(
- "opt-disable", cl::Hidden, cl::CommaSeparated, cl::Optional,
- cl::cb<void, std::string>([](const std::string &Pass) {
- getOptBisector().setDisabled(Pass);
+ "opt-disable", cl::Hidden, cl::Optional,
+ cl::cb<void, std::string>([](const std::string &PassOrIntervalStr) {
+ if (PassOrIntervalStr == "-1") {
+ // -1 means disable all passes.
+ getOptBisector().setDisabledIntervals(
+ {{1, std::numeric_limits<int>::max()}});
+ return;
+ }
+
+ // decide whether to parse this as an interval string or pass name
+ if (isdigit(PassOrIntervalStr[0])) {
+ auto Intervals =
+ IntegerInclusiveIntervalUtils::parseIntervals(PassOrIntervalStr);
+ if (!Intervals) {
+ handleAllErrors(Intervals.takeError(), [&](const StringError &E) {
+ errs() << "Error: Invalid interval specification for -opt-disable: "
+ << PassOrIntervalStr << " (" << E.getMessage() << ")\n";
+ });
+ exit(1);
+ }
+ getOptBisector().setDisabledIntervals(std::move(*Intervals));
+ } else {
+ for (StringRef PassName : llvm::split(PassOrIntervalStr, ','))
+ getOptBisector().setDisabled(PassName);
+ }
}),
cl::desc("Optimization pass(es) to disable (comma-separated list)"));
+static cl::list<std::string> OptBisectFuncsList(
+ "opt-bisect-funcs", cl::value_desc("function names"), cl::CommaSeparated,
+ cl::cb<void, std::string>([](const std::string &FuncName) {
+ getOptBisector().setEnabledFunc(FuncName);
+ }),
+ cl::Hidden,
+ cl::desc("Only perform opt bisect for functions that are included in this "
+ "list and if empty, apply to all functions."));
+
static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
bool Running) {
StringRef Status = Running ? "" : "NOT ";
@@ -93,8 +125,8 @@ static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
<< " on " << TargetDesc << '\n';
}
-bool OptBisect::shouldRunPass(StringRef PassName,
- StringRef IRDescription) const {
+bool OptBisect::shouldRunPass(StringRef PassName, StringRef IRDescription,
+ StringRef FuncName) const {
assert(isEnabled());
int CurBisectNum = ++LastBisectNum;
@@ -108,6 +140,16 @@ bool OptBisect::shouldRunPass(StringRef PassName,
// Also check if the pass is disabled via -opt-disable.
ShouldRun = ShouldRun && !DisabledPasses.contains(PassName);
+ // Also check if the pass is disabled by interval.
+ const int CurDisableNum = ++LastDisableNum;
+ ShouldRun = ShouldRun && !IntegerInclusiveIntervalUtils::contains(
+ DisabledIntervals, CurDisableNum);
+
+ // If passed a function name, check if the function is enabled for bisection
+ // via opt-bisect-funcs
+ bool SkipGate = !FuncName.empty() && !OptBisectFuncNames.empty() &&
+ !OptBisectFuncNames.contains(FuncName);
+ ShouldRun = ShouldRun && !SkipGate;
if (OptBisectVerbose)
printPassMessage(PassName, CurBisectNum, IRDescription, ShouldRun);
diff --git a/llvm/lib/IR/Pass.cpp b/llvm/lib/IR/Pass.cpp
index 08d58379b7e69..c1ce3aef10b57 100644
--- a/llvm/lib/IR/Pass.cpp
+++ b/llvm/lib/IR/Pass.cpp
@@ -197,8 +197,10 @@ bool FunctionPass::skipFunction(const Function &F) const {
if (PassName.empty())
PassName = this->getPassName();
- if (Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(F)))
+ if (Gate.isEnabled() &&
+ !Gate.shouldRunPass(PassName, getDescription(F), F.getName())) {
return true;
+ }
if (F.hasOptNone()) {
LLVM_DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function "
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 9a2225807145a..f0e05c345de02 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -1053,8 +1053,12 @@ bool OptPassGateInstrumentation::shouldRun(StringRef PassName, IRUnitRef IR) {
if (isIgnored(PassName))
return true;
+ StringRef FuncName;
+ if (const auto *F = dyn_cast<Function>(IR))
+ FuncName = F->getName();
+
bool ShouldRun =
- Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
+ Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR), FuncName);
if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
// FIXME: print IR if limit is higher than number of opt-bisect
// invocations
diff --git a/llvm/test/Other/opt-bisect-skip-and-filter.ll b/llvm/test/Other/opt-bisect-skip-and-filter.ll
new file mode 100644
index 0000000000000..76486da6d3e43
--- /dev/null
+++ b/llvm/test/Other/opt-bisect-skip-and-filter.ll
@@ -0,0 +1,107 @@
+; Tests that verify functionality for -opt-disable and -opt-bisect-funcs
+
+; If enabling bisect function filtering, do not skip Module Passes.
+; RUN: opt -disable-output -disable-verify -passes=inferattrs \
+; RUN: -opt-bisect-funcs=f1 -opt-bisect-limit=-1 -opt-bisect-verbose=true %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=CHECK-MODULE-PASS-FILTER
+; CHECK-MODULE-PASS-FILTER: BISECT: running pass (1) inferattrs on [module]
+; CHECK-MODULE-PASS-FILTER-NOT: BISECT: NOT running
+
+; RUN: opt -disable-output -disable-verify \
+; RUN: -passes=early-cse -opt-bisect-limit=-1 -opt-bisect-funcs=f1 -opt-bisect-verbose=true %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=CHECK-FUNCTION-PASS-FILTER
+; CHECK-FUNCTION-PASS-FILTER: BISECT: running pass (1) early-cse on f1
+; CHECK-FUNCTION-PASS-FILTER: BISECT: NOT running pass (2) early-cse on f2
+; CHECK-FUNCTION-PASS-FILTER: BISECT: NOT running pass (3) early-cse on f3
+; CHECK-FUNCTION-PASS-FILTER: BISECT: NOT running pass (4) early-cse on f4
+
+; RUN: opt -disable-output -disable-verify \
+; RUN: -passes=early-cse -opt-bisect-limit=2 -opt-bisect-funcs=f1,f2,f3 -opt-bisect-verbose=true %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-FUNCTION-PASS-FILTER
+; CHECK-LIMIT-FUNCTION-PASS-FILTER: BISECT: running pass (1) early-cse on f1
+; CHECK-LIMIT-FUNCTION-PASS-FILTER: BISECT: running pass (2) early-cse on f2
+; CHECK-LIMIT-FUNCTION-PASS-FILTER: BISECT: NOT running pass (3) early-cse on f3
+; CHECK-LIMIT-FUNCTION-PASS-FILTER: BISECT: NOT running pass (4) early-cse on f4
+
+; RUN: opt -disable-output -disable-verify \
+; RUN: -passes=function-attrs -opt-bisect-limit=-1 -opt-bisect-funcs=f2 -opt-bisect-verbose=true %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=CHECK-CGSCC-PASS-FILTER
+; CHECK-CGSCC-PASS-FILTER: BISECT: running pass (1) function-attrs on (f1)
+; CHECK-CGSCC-PASS-FILTER-NOT: BISECT: Skip bisecting pass 'function-attrs' on
+; CHECK-CGSCC-PASS-FILTER: BISECT: running pass (2) function-attrs on (f2)
+; CHECK-CGSCC-PASS-FILTER: BISECT: running pass (3) function-attrs on (f3)
+; CHECK-CGSCC-PASS-FILTER: BISECT: running pass (4) function-attrs on (f4)
+
+
+; RUN: opt -disable-output -disable-verify -opt-disable=3,7 \
+; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' -opt-bisect-verbose=true %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=CHECK-DISABLE-PASS
+; CHECK-DISABLE-PASS: BISECT: running pass (1) inferattrs on [module]
+; CHECK-DISABLE-PASS: BISECT: running pass (2) function-attrs on (f1)
+; CHECK-DISABLE-PASS: BISECT: NOT running pass (3) early-cse on f1
+; CHECK-DISABLE-PASS: BISECT: running pass (4) function-attrs on (f2)
+; CHECK-DISABLE-PASS: BISECT: running pass (5) early-cse on f2
+; CHECK-DISABLE-PASS: BISECT: running pass (6) function-attrs on (f3)
+; CHECK-DISABLE-PASS: BISECT: NOT running pass (7) early-cse on f3
+; CHECK-DISABLE-PASS: BISECT: running pass (8) function-attrs on (f4)
+; CHECK-DISABLE-PASS: BISECT: running pass (9) early-cse on f4
+
+declare i32 @g()
+
+define void @f1() {
+entry:
+ br label %loop.0
+loop.0:
+ br i1 undef, label %loop.0.0, label %loop.1
+loop.0.0:
+ br i1 undef, label %loop.0.0, label %loop.0.1
+loop.0.1:
+ br i1 undef, label %loop.0.1, label %loop.0
+loop.1:
+ br i1 undef, label %loop.1, label %loop.1.bb1
+loop.1.bb1:
+ br i1 undef, label %loop.1, label %loop.1.bb2
+loop.1.bb2:
+ br i1 undef, label %end, label %loop.1.0
+loop.1.0:
+ br i1 undef, label %loop.1.0, label %loop.1
+end:
+ ret void
+}
+
+define i32 @f2() {
+entry:
+ ret i32 0
+}
+
+define i32 @f3() {
+entry:
+ %temp = call i32 @g()
+ %icmp = icmp ugt i32 %temp, 2
+ br i1 %icmp, label %bb.true, label %bb.false
+bb.true:
+ %temp2 = call i32 @f2()
+ ret i32 %temp2
+bb.false:
+ ret i32 0
+}
+
+; This function is here to verify that opt-bisect can skip all passes for
+; functions that contain lifetime intrinsics.
+define void @f4() {
+entry:
+ %i = alloca i32, align 4
+ call void @llvm.lifetime.start(i64 4, ptr %i)
+ br label %for.cond
+
+for.cond:
+ br i1 undef, label %for.body, label %for.end
+
+for.body:
+ br label %for.cond
+
+for.end:
+ ret void
+}
+
+declare void @llvm.lifetime.start(i64, ptr nocapture)
>From f6dcdc2b6199ea172f55b42ee3fc0f481fe655f8 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Tue, 8 Sep 2026 20:27:36 +0000
Subject: [PATCH 2/5] Fix undef issues in test
---
llvm/test/Other/opt-bisect-skip-and-filter.ll | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/llvm/test/Other/opt-bisect-skip-and-filter.ll b/llvm/test/Other/opt-bisect-skip-and-filter.ll
index 76486da6d3e43..78a261cbbe6ca 100644
--- a/llvm/test/Other/opt-bisect-skip-and-filter.ll
+++ b/llvm/test/Other/opt-bisect-skip-and-filter.ll
@@ -48,23 +48,24 @@
declare i32 @g()
-define void @f1() {
+define void @f1(i1 %cond0, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4,
+ i1 %cond5, i1 %cond6) {
entry:
br label %loop.0
loop.0:
- br i1 undef, label %loop.0.0, label %loop.1
+ br i1 %cond0, label %loop.0.0, label %loop.1
loop.0.0:
- br i1 undef, label %loop.0.0, label %loop.0.1
+ br i1 %cond1, label %loop.0.0, label %loop.0.1
loop.0.1:
- br i1 undef, label %loop.0.1, label %loop.0
+ br i1 %cond2, label %loop.0.1, label %loop.0
loop.1:
- br i1 undef, label %loop.1, label %loop.1.bb1
+ br i1 %cond3, label %loop.1, label %loop.1.bb1
loop.1.bb1:
- br i1 undef, label %loop.1, label %loop.1.bb2
+ br i1 %cond4, label %loop.1, label %loop.1.bb2
loop.1.bb2:
- br i1 undef, label %end, label %loop.1.0
+ br i1 %cond5, label %end, label %loop.1.0
loop.1.0:
- br i1 undef, label %loop.1.0, label %loop.1
+ br i1 %cond6, label %loop.1.0, label %loop.1
end:
ret void
}
@@ -88,14 +89,14 @@ bb.false:
; This function is here to verify that opt-bisect can skip all passes for
; functions that contain lifetime intrinsics.
-define void @f4() {
+define void @f4(i1 %cond) {
entry:
%i = alloca i32, align 4
call void @llvm.lifetime.start(i64 4, ptr %i)
br label %for.cond
for.cond:
- br i1 undef, label %for.body, label %for.end
+ br i1 %cond, label %for.body, label %for.end
for.body:
br label %for.cond
>From 75ef565f872abb1d6d2877b485bf7ce2ed6679c2 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Wed, 9 Sep 2026 15:05:52 +0000
Subject: [PATCH 3/5] Add interval test for opt-disable
---
llvm/test/Other/opt-bisect-skip-and-filter.ll | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/llvm/test/Other/opt-bisect-skip-and-filter.ll b/llvm/test/Other/opt-bisect-skip-and-filter.ll
index 78a261cbbe6ca..0f8c57bc8e163 100644
--- a/llvm/test/Other/opt-bisect-skip-and-filter.ll
+++ b/llvm/test/Other/opt-bisect-skip-and-filter.ll
@@ -46,6 +46,19 @@
; CHECK-DISABLE-PASS: BISECT: running pass (8) function-attrs on (f4)
; CHECK-DISABLE-PASS: BISECT: running pass (9) early-cse on f4
+; RUN: opt -disable-output -disable-verify -opt-disable=3-7 \
+; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' -opt-bisect-verbose=true %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=CHECK-DISABLE-INTERVAL
+; CHECK-DISABLE-INTERVAL: BISECT: running pass (1) inferattrs on [module]
+; CHECK-DISABLE-INTERVAL: BISECT: running pass (2) function-attrs on (f1)
+; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (3) early-cse on f1
+; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (4) function-attrs on (f2)
+; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (5) early-cse on f2
+; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (6) function-attrs on (f3)
+; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (7) early-cse on f3
+; CHECK-DISABLE-INTERVAL: BISECT: running pass (8) function-attrs on (f4)
+; CHECK-DISABLE-INTERVAL: BISECT: running pass (9) early-cse on f4
+
declare i32 @g()
define void @f1(i1 %cond0, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4,
>From 978fd263620ec00130700a03080f5c398abaf320 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Wed, 16 Sep 2026 15:30:00 +0000
Subject: [PATCH 4/5] Remove disable intervals support
---
llvm/include/llvm/IR/OptBisect.h | 19 +----------
llvm/lib/IR/OptBisect.cpp | 33 ++-----------------
...skip-and-filter.ll => opt-bisect-funcs.ll} | 28 +---------------
3 files changed, 5 insertions(+), 75 deletions(-)
rename llvm/test/Other/{opt-bisect-skip-and-filter.ll => opt-bisect-funcs.ll} (64%)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 7198daf507dfd..8688457002615 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -14,7 +14,6 @@
#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"
@@ -79,14 +78,12 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// isEnabled() should return true before calling shouldRunPass().
bool isEnabled() const override {
- return !BisectIntervals.empty() || !DisabledPasses.empty() ||
- !DisabledIntervals.empty();
+ return !BisectIntervals.empty() || !DisabledPasses.empty();
}
void reset() override {
clearIntervals();
DisabledPasses.clear();
- clearDisabledIntervals();
clearEnabledFuncs();
}
@@ -105,18 +102,6 @@ class LLVM_ABI OptBisect : public OptPassGate {
/// to be disabled. Multiple pass names can be provided with comma separation.
void setDisabled(StringRef Pass) { DisabledPasses.insert(Pass); }
- /// Set intervals directly from an IntervalList.
- void
- setDisabledIntervals(IntegerInclusiveIntervalUtils::IntervalList Intervals) {
- DisabledIntervals.append(Intervals);
- }
-
- /// Clear all disabled intervals.
- void clearDisabledIntervals() {
- DisabledIntervals.clear();
- LastDisableNum = 0;
- }
-
/// Add a function name to the set of functions enabled for opt bisect.
void setEnabledFunc(StringRef FuncName) {
OptBisectFuncNames.insert(FuncName);
@@ -131,8 +116,6 @@ class LLVM_ABI OptBisect : public OptPassGate {
IntegerInclusiveIntervalUtils::IntervalList BisectIntervals;
StringSet<> DisabledPasses = {};
- IntegerInclusiveIntervalUtils::IntervalList DisabledIntervals;
- mutable int LastDisableNum = 0;
StringSet<> OptBisectFuncNames = {};
};
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 3c44a411ff21c..972ab636ec7a4 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -79,33 +79,10 @@ static cl::opt<bool> OptBisectVerbose(
"Show verbose output when opt-bisect-limit and/or opt-disable are set"),
cl::Hidden, cl::init(true), cl::Optional);
-// Augment -opt-disable to support intervals in addition to pass names
static cl::list<std::string> OptDisablePasses(
- "opt-disable", cl::Hidden, cl::Optional,
- cl::cb<void, std::string>([](const std::string &PassOrIntervalStr) {
- if (PassOrIntervalStr == "-1") {
- // -1 means disable all passes.
- getOptBisector().setDisabledIntervals(
- {{1, std::numeric_limits<int>::max()}});
- return;
- }
-
- // decide whether to parse this as an interval string or pass name
- if (isdigit(PassOrIntervalStr[0])) {
- auto Intervals =
- IntegerInclusiveIntervalUtils::parseIntervals(PassOrIntervalStr);
- if (!Intervals) {
- handleAllErrors(Intervals.takeError(), [&](const StringError &E) {
- errs() << "Error: Invalid interval specification for -opt-disable: "
- << PassOrIntervalStr << " (" << E.getMessage() << ")\n";
- });
- exit(1);
- }
- getOptBisector().setDisabledIntervals(std::move(*Intervals));
- } else {
- for (StringRef PassName : llvm::split(PassOrIntervalStr, ','))
- getOptBisector().setDisabled(PassName);
- }
+ "opt-disable", cl::Hidden, cl::CommaSeparated, cl::Optional,
+ cl::cb<void, std::string>([](const std::string &Pass) {
+ getOptBisector().setDisabled(Pass);
}),
cl::desc("Optimization pass(es) to disable (comma-separated list)"));
@@ -140,10 +117,6 @@ bool OptBisect::shouldRunPass(StringRef PassName, StringRef IRDescription,
// Also check if the pass is disabled via -opt-disable.
ShouldRun = ShouldRun && !DisabledPasses.contains(PassName);
- // Also check if the pass is disabled by interval.
- const int CurDisableNum = ++LastDisableNum;
- ShouldRun = ShouldRun && !IntegerInclusiveIntervalUtils::contains(
- DisabledIntervals, CurDisableNum);
// If passed a function name, check if the function is enabled for bisection
// via opt-bisect-funcs
diff --git a/llvm/test/Other/opt-bisect-skip-and-filter.ll b/llvm/test/Other/opt-bisect-funcs.ll
similarity index 64%
rename from llvm/test/Other/opt-bisect-skip-and-filter.ll
rename to llvm/test/Other/opt-bisect-funcs.ll
index 0f8c57bc8e163..076ecb28abb69 100644
--- a/llvm/test/Other/opt-bisect-skip-and-filter.ll
+++ b/llvm/test/Other/opt-bisect-funcs.ll
@@ -1,4 +1,4 @@
-; Tests that verify functionality for -opt-disable and -opt-bisect-funcs
+; Tests that verify functionality for -opt-bisect-funcs
; If enabling bisect function filtering, do not skip Module Passes.
; RUN: opt -disable-output -disable-verify -passes=inferattrs \
@@ -33,32 +33,6 @@
; CHECK-CGSCC-PASS-FILTER: BISECT: running pass (4) function-attrs on (f4)
-; RUN: opt -disable-output -disable-verify -opt-disable=3,7 \
-; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' -opt-bisect-verbose=true %s 2>&1 \
-; RUN: | FileCheck %s --check-prefix=CHECK-DISABLE-PASS
-; CHECK-DISABLE-PASS: BISECT: running pass (1) inferattrs on [module]
-; CHECK-DISABLE-PASS: BISECT: running pass (2) function-attrs on (f1)
-; CHECK-DISABLE-PASS: BISECT: NOT running pass (3) early-cse on f1
-; CHECK-DISABLE-PASS: BISECT: running pass (4) function-attrs on (f2)
-; CHECK-DISABLE-PASS: BISECT: running pass (5) early-cse on f2
-; CHECK-DISABLE-PASS: BISECT: running pass (6) function-attrs on (f3)
-; CHECK-DISABLE-PASS: BISECT: NOT running pass (7) early-cse on f3
-; CHECK-DISABLE-PASS: BISECT: running pass (8) function-attrs on (f4)
-; CHECK-DISABLE-PASS: BISECT: running pass (9) early-cse on f4
-
-; RUN: opt -disable-output -disable-verify -opt-disable=3-7 \
-; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' -opt-bisect-verbose=true %s 2>&1 \
-; RUN: | FileCheck %s --check-prefix=CHECK-DISABLE-INTERVAL
-; CHECK-DISABLE-INTERVAL: BISECT: running pass (1) inferattrs on [module]
-; CHECK-DISABLE-INTERVAL: BISECT: running pass (2) function-attrs on (f1)
-; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (3) early-cse on f1
-; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (4) function-attrs on (f2)
-; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (5) early-cse on f2
-; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (6) function-attrs on (f3)
-; CHECK-DISABLE-INTERVAL: BISECT: NOT running pass (7) early-cse on f3
-; CHECK-DISABLE-INTERVAL: BISECT: running pass (8) function-attrs on (f4)
-; CHECK-DISABLE-INTERVAL: BISECT: running pass (9) early-cse on f4
-
declare i32 @g()
define void @f1(i1 %cond0, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4,
>From b65688f36b57768876bb6594c0b30cae15994f04 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Mon, 21 Sep 2026 14:15:10 +0000
Subject: [PATCH 5/5] Address feedback
---
llvm/include/llvm/IR/OptBisect.h | 8 ++------
llvm/lib/IR/OptBisect.cpp | 2 +-
llvm/lib/IR/Pass.cpp | 3 ++-
3 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h
index 8688457002615..6e0bce76512d7 100644
--- a/llvm/include/llvm/IR/OptBisect.h
+++ b/llvm/include/llvm/IR/OptBisect.h
@@ -28,12 +28,8 @@ class OptPassGate {
virtual ~OptPassGate() = default;
/// IRDescription is a textual description of the IR unit the pass is running
- /// over.
- virtual bool shouldRunPass(StringRef PassName,
- StringRef IRDescription) const {
- return shouldRunPass(PassName, IRDescription, "");
- }
-
+ /// over. FuncName is the name of the function or the empty string if a module
+ /// level pass is being run.
virtual bool shouldRunPass(StringRef PassName, StringRef IRDescription,
StringRef FuncName) const {
return true;
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
index 972ab636ec7a4..3fd2e3744ff25 100644
--- a/llvm/lib/IR/OptBisect.cpp
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -119,7 +119,7 @@ bool OptBisect::shouldRunPass(StringRef PassName, StringRef IRDescription,
ShouldRun = ShouldRun && !DisabledPasses.contains(PassName);
// If passed a function name, check if the function is enabled for bisection
- // via opt-bisect-funcs
+ // via opt-bisect-funcs.
bool SkipGate = !FuncName.empty() && !OptBisectFuncNames.empty() &&
!OptBisectFuncNames.contains(FuncName);
ShouldRun = ShouldRun && !SkipGate;
diff --git a/llvm/lib/IR/Pass.cpp b/llvm/lib/IR/Pass.cpp
index bf3472c0908b9..dbcd794a5d46b 100644
--- a/llvm/lib/IR/Pass.cpp
+++ b/llvm/lib/IR/Pass.cpp
@@ -68,7 +68,8 @@ bool ModulePass::skipModule(const Module &M) const {
if (PassName.empty())
PassName = this->getPassName();
- return Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(M));
+ return Gate.isEnabled() &&
+ !Gate.shouldRunPass(PassName, getDescription(M), "");
}
bool Pass::mustPreserveAnalysisID(char &AID) const {
More information about the llvm-commits
mailing list