Skip to content

Commit 81eb7de

Browse files
[OptBisect][IR] Adding a new OptPassGate for disabling passes via name (#145059)
This commit adds a new pass gate that allows selective disabling of one or more passes via the clang command line using the `-opt-disable` option. Passes to be disabled should be specified as a comma-separated list of their names. The implementation resides in the same file as the bisection tool. The `getGlobalPassGate()` function returns the currently enabled gate. Example: `-opt-disable="PassA,PassB"` Pass names are matched using case-insensitive comparisons. However, note that special characters, including spaces, must be included exactly as they appear in the pass names. Additionally, a `-opt-disable-enable-verbosity` flag has been introduced to enable verbose output when this functionality is in use. When enabled, it prints the status of all passes (either running or NOT running), similar to the default behavior of `-opt-bisect-limit`. This flag is disabled by default, which is the opposite of the `-opt-bisect-verbose` flag (which defaults to enabled). To validate this functionality, a test file has also been provided. It reuses the same infrastructure as the opt-bisect test, but disables three specific passes and checks the output to ensure the expected behavior. --------- Co-authored-by: Nikita Popov <[email protected]>
1 parent 26b0b27 commit 81eb7de

File tree

8 files changed

+237
-49
lines changed

8 files changed

+237
-49
lines changed

clang/test/CodeGen/new-pass-manager-opt-bisect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
// CHECK: BISECT: running pass (1)
88
// CHECK-NOT: BISECT: running pass (1)
99
// Make sure that legacy pass manager is running
10-
// CHECK: Instruction Selection
10+
// CHECK: -isel
1111

1212
int func(int a) { return a; }

llvm/include/llvm/IR/OptBisect.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_IR_OPTBISECT_H
1616

1717
#include "llvm/ADT/StringRef.h"
18+
#include "llvm/ADT/StringSet.h"
1819
#include "llvm/Support/Compiler.h"
1920
#include <limits>
2021

@@ -82,8 +83,38 @@ class LLVM_ABI OptBisect : public OptPassGate {
8283
mutable int LastBisectNum = 0;
8384
};
8485

85-
/// Singleton instance of the OptBisect class, so multiple pass managers don't
86-
/// need to coordinate their uses of OptBisect.
86+
/// This class implements a mechanism to disable passes and individual
87+
/// optimizations at compile time based on a command line option
88+
/// (-opt-disable) in order to study how single transformations, or
89+
/// combinations thereof, affect the IR.
90+
class LLVM_ABI OptDisable : public OptPassGate {
91+
public:
92+
/// Checks the pass name to determine if the specified pass should run.
93+
///
94+
/// It returns true if the pass should run, i.e. if its name is was
95+
/// not provided via command line.
96+
/// If -opt-disable-enable-verbosity is given, the method prints the
97+
/// name of the pass, and whether or not the pass will be executed.
98+
///
99+
/// Most passes should not call this routine directly. Instead, it is called
100+
/// through helper routines provided by the base classes of the pass. For
101+
/// instance, function passes should call FunctionPass::skipFunction().
102+
bool shouldRunPass(StringRef PassName,
103+
StringRef IRDescription) const override;
104+
105+
/// Parses the command line argument to extract the names of the passes
106+
/// to be disabled. Multiple pass names can be provided with comma separation.
107+
void setDisabled(StringRef Pass);
108+
109+
/// isEnabled() should return true before calling shouldRunPass().
110+
bool isEnabled() const override { return !DisabledPasses.empty(); }
111+
112+
private:
113+
StringSet<> DisabledPasses = {};
114+
};
115+
116+
/// Singleton instance of the OptPassGate class, so multiple pass managers don't
117+
/// need to coordinate their uses of OptBisect and OptDisable.
87118
LLVM_ABI OptPassGate &getGlobalPassGate();
88119

89120
} // end namespace llvm

llvm/include/llvm/Pass.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class LLVM_ABI Pass {
114114
/// Registration templates, but can be overloaded directly.
115115
virtual StringRef getPassName() const;
116116

117+
/// Return a nice clean name for a pass
118+
/// corresponding to that used to enable the pass in opt.
119+
StringRef getPassArgument() const;
120+
117121
/// getPassID - Return the PassID number that corresponds to this pass.
118122
AnalysisID getPassID() const {
119123
return PassID;

llvm/lib/IR/OptBisect.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ static OptBisect &getOptBisector() {
2525
return OptBisector;
2626
}
2727

28+
static OptDisable &getOptDisabler() {
29+
static OptDisable OptDisabler;
30+
return OptDisabler;
31+
}
32+
2833
static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
2934
cl::init(OptBisect::Disabled), cl::Optional,
3035
cl::cb<void, int>([](int Limit) {
@@ -37,6 +42,18 @@ static cl::opt<bool> OptBisectVerbose(
3742
cl::desc("Show verbose output when opt-bisect-limit is set"), cl::Hidden,
3843
cl::init(true), cl::Optional);
3944

45+
static cl::list<std::string> OptDisablePasses(
46+
"opt-disable", cl::Hidden, cl::CommaSeparated, cl::Optional,
47+
cl::cb<void, std::string>([](const std::string &Pass) {
48+
getOptDisabler().setDisabled(Pass);
49+
}),
50+
cl::desc("Optimization pass(es) to disable (comma-separated list)"));
51+
52+
static cl::opt<bool>
53+
OptDisableVerbose("opt-disable-enable-verbosity",
54+
cl::desc("Show verbose output when opt-disable is set"),
55+
cl::Hidden, cl::init(false), cl::Optional);
56+
4057
static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
4158
bool Running) {
4259
StringRef Status = Running ? "" : "NOT ";
@@ -55,4 +72,27 @@ bool OptBisect::shouldRunPass(StringRef PassName,
5572
return ShouldRun;
5673
}
5774

58-
OptPassGate &llvm::getGlobalPassGate() { return getOptBisector(); }
75+
static void printDisablePassMessage(const StringRef &Name, StringRef TargetDesc,
76+
bool Running) {
77+
StringRef Status = Running ? "" : "NOT ";
78+
dbgs() << "OptDisable: " << Status << "running pass " << Name << " on "
79+
<< TargetDesc << "\n";
80+
}
81+
82+
void OptDisable::setDisabled(StringRef Pass) { DisabledPasses.insert(Pass); }
83+
84+
bool OptDisable::shouldRunPass(StringRef PassName,
85+
StringRef IRDescription) const {
86+
assert(isEnabled());
87+
88+
const bool ShouldRun = !DisabledPasses.contains(PassName);
89+
if (OptDisableVerbose)
90+
printDisablePassMessage(PassName, IRDescription, ShouldRun);
91+
return ShouldRun;
92+
}
93+
94+
OptPassGate &llvm::getGlobalPassGate() {
95+
if (getOptDisabler().isEnabled())
96+
return getOptDisabler();
97+
return getOptBisector();
98+
}

llvm/lib/IR/Pass.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ static std::string getDescription(const Module &M) {
6262

6363
bool ModulePass::skipModule(const Module &M) const {
6464
const OptPassGate &Gate = M.getContext().getOptPassGate();
65-
return Gate.isEnabled() &&
66-
!Gate.shouldRunPass(this->getPassName(), getDescription(M));
65+
66+
StringRef PassName = getPassArgument();
67+
if (PassName.empty())
68+
PassName = this->getPassName();
69+
70+
return Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(M));
6771
}
6872

6973
bool Pass::mustPreserveAnalysisID(char &AID) const {
@@ -86,6 +90,16 @@ StringRef Pass::getPassName() const {
8690
return "Unnamed pass: implement Pass::getPassName()";
8791
}
8892

93+
/// getPassArgument - Return a nice clean name for a pass
94+
/// corresponding to that used to enable the pass in opt
95+
StringRef Pass::getPassArgument() const {
96+
AnalysisID AID = getPassID();
97+
const PassInfo *PI = Pass::lookupPassInfo(AID);
98+
if (PI)
99+
return PI->getPassArgument();
100+
return "";
101+
}
102+
89103
void Pass::preparePassManager(PMStack &) {
90104
// By default, don't do anything.
91105
}
@@ -173,8 +187,12 @@ static std::string getDescription(const Function &F) {
173187

174188
bool FunctionPass::skipFunction(const Function &F) const {
175189
OptPassGate &Gate = F.getContext().getOptPassGate();
176-
if (Gate.isEnabled() &&
177-
!Gate.shouldRunPass(this->getPassName(), getDescription(F)))
190+
191+
StringRef PassName = getPassArgument();
192+
if (PassName.empty())
193+
PassName = this->getPassName();
194+
195+
if (Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(F)))
178196
return true;
179197

180198
if (F.hasOptNone()) {

llvm/lib/Passes/StandardInstrumentations.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,9 +1078,13 @@ void OptPassGateInstrumentation::registerCallbacks(
10781078
if (!PassGate.isEnabled())
10791079
return;
10801080

1081-
PIC.registerShouldRunOptionalPassCallback([this](StringRef PassName, Any IR) {
1082-
return this->shouldRun(PassName, IR);
1083-
});
1081+
PIC.registerShouldRunOptionalPassCallback(
1082+
[this, &PIC](StringRef ClassName, Any IR) {
1083+
StringRef PassName = PIC.getPassNameForClassName(ClassName);
1084+
if (PassName.empty())
1085+
return this->shouldRun(ClassName, IR);
1086+
return this->shouldRun(PassName, IR);
1087+
});
10841088
}
10851089

10861090
raw_ostream &PrintPassInstrumentation::print() {

llvm/test/Other/opt-bisect-new-pass-manager.ll

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,84 +11,84 @@
1111
; RUN: opt -disable-output -disable-verify \
1212
; RUN: -passes=inferattrs -opt-bisect-limit=-1 %s 2>&1 \
1313
; RUN: | FileCheck %s --check-prefix=CHECK-MODULE-PASS
14-
; CHECK-MODULE-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module]
14+
; CHECK-MODULE-PASS: BISECT: running pass (1) inferattrs on [module]
1515

1616
; RUN: opt -disable-output -disable-verify \
1717
; RUN: -passes=inferattrs -opt-bisect-limit=0 %s 2>&1 \
1818
; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-MODULE-PASS
19-
; CHECK-LIMIT-MODULE-PASS: BISECT: NOT running pass (1) InferFunctionAttrsPass on [module]
19+
; CHECK-LIMIT-MODULE-PASS: BISECT: NOT running pass (1) inferattrs on [module]
2020

2121
; RUN: opt -disable-output -debug-pass-manager \
2222
; RUN: -passes=inferattrs -opt-bisect-limit=-1 %s 2>&1 \
2323
; RUN: | FileCheck %s --check-prefix=CHECK-REQUIRED-PASS
24-
; CHECK-REQUIRED-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module]
24+
; CHECK-REQUIRED-PASS: BISECT: running pass (1) inferattrs on [module]
2525
; CHECK-REQUIRED-PASS-NOT: BISECT: {{.*}}VerifierPass
2626
; CHECK-REQUIRED-PASS: Running pass: VerifierPass
2727

2828
; RUN: opt -disable-output -debug-pass-manager \
2929
; RUN: -passes=inferattrs -opt-bisect-limit=0 %s 2>&1 \
3030
; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-REQUIRED-PASS
31-
; CHECK-LIMIT-REQUIRED-PASS: BISECT: NOT running pass (1) InferFunctionAttrsPass on [module]
31+
; CHECK-LIMIT-REQUIRED-PASS: BISECT: NOT running pass (1) inferattrs on [module]
3232
; CHECK-LIMIT-REQUIRED-PASS-NOT: BISECT: {{.*}}VerifierPass
3333
; CHECK-LIMIT-REQUIRED-PASS: Running pass: VerifierPass
3434

3535
; RUN: opt -disable-output -disable-verify \
3636
; RUN: -passes=early-cse -opt-bisect-limit=-1 %s 2>&1 \
3737
; RUN: | FileCheck %s --check-prefix=CHECK-FUNCTION-PASS
38-
; CHECK-FUNCTION-PASS: BISECT: running pass (1) EarlyCSEPass on f1
39-
; CHECK-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on f2
40-
; CHECK-FUNCTION-PASS: BISECT: running pass (3) EarlyCSEPass on f3
41-
; CHECK-FUNCTION-PASS: BISECT: running pass (4) EarlyCSEPass on f4
38+
; CHECK-FUNCTION-PASS: BISECT: running pass (1) early-cse on f1
39+
; CHECK-FUNCTION-PASS: BISECT: running pass (2) early-cse on f2
40+
; CHECK-FUNCTION-PASS: BISECT: running pass (3) early-cse on f3
41+
; CHECK-FUNCTION-PASS: BISECT: running pass (4) early-cse on f4
4242

4343
; RUN: opt -disable-output -disable-verify \
4444
; RUN: -passes=early-cse -opt-bisect-limit=2 %s 2>&1 \
4545
; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-FUNCTION-PASS
46-
; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (1) EarlyCSEPass on f1
47-
; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on f2
48-
; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (3) EarlyCSEPass on f3
49-
; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (4) EarlyCSEPass on f4
46+
; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (1) early-cse on f1
47+
; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (2) early-cse on f2
48+
; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (3) early-cse on f3
49+
; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (4) early-cse on f4
5050

5151
; RUN: opt -disable-output -disable-verify \
5252
; RUN: -passes=function-attrs -opt-bisect-limit=-1 %s 2>&1 \
5353
; RUN: | FileCheck %s --check-prefix=CHECK-CGSCC-PASS
54-
; CHECK-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on (f1)
55-
; CHECK-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f2)
56-
; CHECK-CGSCC-PASS: BISECT: running pass (3) PostOrderFunctionAttrsPass on (f3)
57-
; CHECK-CGSCC-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on (f4)
54+
; CHECK-CGSCC-PASS: BISECT: running pass (1) function-attrs on (f1)
55+
; CHECK-CGSCC-PASS: BISECT: running pass (2) function-attrs on (f2)
56+
; CHECK-CGSCC-PASS: BISECT: running pass (3) function-attrs on (f3)
57+
; CHECK-CGSCC-PASS: BISECT: running pass (4) function-attrs on (f4)
5858

5959
; RUN: opt -disable-output -disable-verify \
6060
; RUN: -passes=function-attrs -opt-bisect-limit=3 %s 2>&1 \
6161
; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-CGSCC-PASS
62-
; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on (f1)
63-
; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f2)
64-
; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (3) PostOrderFunctionAttrsPass on (f3)
65-
; CHECK-LIMIT-CGSCC-PASS: BISECT: NOT running pass (4) PostOrderFunctionAttrsPass on (f4)
62+
; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (1) function-attrs on (f1)
63+
; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (2) function-attrs on (f2)
64+
; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (3) function-attrs on (f3)
65+
; CHECK-LIMIT-CGSCC-PASS: BISECT: NOT running pass (4) function-attrs on (f4)
6666

6767
; RUN: opt -disable-output -disable-verify -opt-bisect-limit=-1 \
6868
; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \
6969
; RUN: | FileCheck %s --check-prefix=CHECK-MULTI-PASS
70-
; CHECK-MULTI-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module]
71-
; CHECK-MULTI-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f1)
72-
; CHECK-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on f1
73-
; CHECK-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on (f2)
74-
; CHECK-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on f2
75-
; CHECK-MULTI-PASS: BISECT: running pass (6) PostOrderFunctionAttrsPass on (f3)
76-
; CHECK-MULTI-PASS: BISECT: running pass (7) EarlyCSEPass on f3
77-
; CHECK-MULTI-PASS: BISECT: running pass (8) PostOrderFunctionAttrsPass on (f4)
78-
; CHECK-MULTI-PASS: BISECT: running pass (9) EarlyCSEPass on f4
70+
; CHECK-MULTI-PASS: BISECT: running pass (1) inferattrs on [module]
71+
; CHECK-MULTI-PASS: BISECT: running pass (2) function-attrs on (f1)
72+
; CHECK-MULTI-PASS: BISECT: running pass (3) early-cse on f1
73+
; CHECK-MULTI-PASS: BISECT: running pass (4) function-attrs on (f2)
74+
; CHECK-MULTI-PASS: BISECT: running pass (5) early-cse on f2
75+
; CHECK-MULTI-PASS: BISECT: running pass (6) function-attrs on (f3)
76+
; CHECK-MULTI-PASS: BISECT: running pass (7) early-cse on f3
77+
; CHECK-MULTI-PASS: BISECT: running pass (8) function-attrs on (f4)
78+
; CHECK-MULTI-PASS: BISECT: running pass (9) early-cse on f4
7979

8080
; RUN: opt -disable-output -disable-verify -opt-bisect-limit=7 \
8181
; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \
8282
; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-MULTI-PASS
83-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module]
84-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f1)
85-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on f1
86-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on (f2)
87-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on f2
88-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (6) PostOrderFunctionAttrsPass on (f3)
89-
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (7) EarlyCSEPass on f3
90-
; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (8) PostOrderFunctionAttrsPass on (f4)
91-
; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (9) EarlyCSEPass on f4
83+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (1) inferattrs on [module]
84+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (2) function-attrs on (f1)
85+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (3) early-cse on f1
86+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (4) function-attrs on (f2)
87+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (5) early-cse on f2
88+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (6) function-attrs on (f3)
89+
; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (7) early-cse on f3
90+
; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (8) function-attrs on (f4)
91+
; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (9) early-cse on f4
9292

9393
; Make sure we don't skip writing the output to stdout.
9494
; RUN: opt %s -opt-bisect-limit=0 -passes=early-cse | opt -S | FileCheck %s -check-prefix=CHECK-OUTPUT

0 commit comments

Comments
 (0)