diff --git a/clang/test/CodeGen/new-pass-manager-opt-bisect.c b/clang/test/CodeGen/new-pass-manager-opt-bisect.c index 91a0adf252bb5..5d5fdd473422a 100644 --- a/clang/test/CodeGen/new-pass-manager-opt-bisect.c +++ b/clang/test/CodeGen/new-pass-manager-opt-bisect.c @@ -7,6 +7,6 @@ // CHECK: BISECT: running pass (1) // CHECK-NOT: BISECT: running pass (1) // Make sure that legacy pass manager is running -// CHECK: Instruction Selection +// CHECK: -isel int func(int a) { return a; } diff --git a/llvm/include/llvm/IR/OptBisect.h b/llvm/include/llvm/IR/OptBisect.h index ea3c1defeb100..d813ae933d65e 100644 --- a/llvm/include/llvm/IR/OptBisect.h +++ b/llvm/include/llvm/IR/OptBisect.h @@ -15,6 +15,7 @@ #define LLVM_IR_OPTBISECT_H #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Compiler.h" #include @@ -82,8 +83,38 @@ class LLVM_ABI OptBisect : public OptPassGate { mutable int LastBisectNum = 0; }; -/// Singleton instance of the OptBisect class, so multiple pass managers don't -/// need to coordinate their uses of OptBisect. +/// This class implements a mechanism to disable passes and individual +/// optimizations at compile time based on a command line option +/// (-opt-disable) in order to study how single transformations, or +/// combinations thereof, affect the IR. +class LLVM_ABI OptDisable : public OptPassGate { +public: + /// Checks the pass name to determine if the specified pass should run. + /// + /// It returns true if the pass should run, i.e. if its name is was + /// not provided via command line. + /// If -opt-disable-enable-verbosity is given, the method prints the + /// name of the pass, and whether or not the pass will be executed. + /// + /// 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; + + /// Parses the command line argument to extract the names of the passes + /// to be disabled. Multiple pass names can be provided with comma separation. + void setDisabled(StringRef Pass); + + /// isEnabled() should return true before calling shouldRunPass(). + bool isEnabled() const override { return !DisabledPasses.empty(); } + +private: + StringSet<> DisabledPasses = {}; +}; + +/// Singleton instance of the OptPassGate class, so multiple pass managers don't +/// need to coordinate their uses of OptBisect and OptDisable. LLVM_ABI OptPassGate &getGlobalPassGate(); } // end namespace llvm diff --git a/llvm/include/llvm/Pass.h b/llvm/include/llvm/Pass.h index 2ecd47dd10bde..f3962c3556c95 100644 --- a/llvm/include/llvm/Pass.h +++ b/llvm/include/llvm/Pass.h @@ -114,6 +114,10 @@ class LLVM_ABI Pass { /// Registration templates, but can be overloaded directly. virtual StringRef getPassName() const; + /// Return a nice clean name for a pass + /// corresponding to that used to enable the pass in opt. + StringRef getPassArgument() const; + /// getPassID - Return the PassID number that corresponds to this pass. AnalysisID getPassID() const { return PassID; diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp index 427e8b78fd03f..29ca268408265 100644 --- a/llvm/lib/IR/OptBisect.cpp +++ b/llvm/lib/IR/OptBisect.cpp @@ -25,6 +25,11 @@ static OptBisect &getOptBisector() { return OptBisector; } +static OptDisable &getOptDisabler() { + static OptDisable OptDisabler; + return OptDisabler; +} + static cl::opt OptBisectLimit("opt-bisect-limit", cl::Hidden, cl::init(OptBisect::Disabled), cl::Optional, cl::cb([](int Limit) { @@ -37,6 +42,18 @@ static cl::opt OptBisectVerbose( cl::desc("Show verbose output when opt-bisect-limit is set"), cl::Hidden, cl::init(true), cl::Optional); +static cl::list OptDisablePasses( + "opt-disable", cl::Hidden, cl::CommaSeparated, cl::Optional, + cl::cb([](const std::string &Pass) { + getOptDisabler().setDisabled(Pass); + }), + cl::desc("Optimization pass(es) to disable (comma-separated list)")); + +static cl::opt + OptDisableVerbose("opt-disable-enable-verbosity", + cl::desc("Show verbose output when opt-disable is set"), + cl::Hidden, cl::init(false), cl::Optional); + static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc, bool Running) { StringRef Status = Running ? "" : "NOT "; @@ -55,4 +72,27 @@ bool OptBisect::shouldRunPass(StringRef PassName, return ShouldRun; } -OptPassGate &llvm::getGlobalPassGate() { return getOptBisector(); } +static void printDisablePassMessage(const StringRef &Name, StringRef TargetDesc, + bool Running) { + StringRef Status = Running ? "" : "NOT "; + dbgs() << "OptDisable: " << Status << "running pass " << Name << " on " + << TargetDesc << "\n"; +} + +void OptDisable::setDisabled(StringRef Pass) { DisabledPasses.insert(Pass); } + +bool OptDisable::shouldRunPass(StringRef PassName, + StringRef IRDescription) const { + assert(isEnabled()); + + const bool ShouldRun = !DisabledPasses.contains(PassName); + if (OptDisableVerbose) + printDisablePassMessage(PassName, IRDescription, ShouldRun); + return ShouldRun; +} + +OptPassGate &llvm::getGlobalPassGate() { + if (getOptDisabler().isEnabled()) + return getOptDisabler(); + return getOptBisector(); +} diff --git a/llvm/lib/IR/Pass.cpp b/llvm/lib/IR/Pass.cpp index 2c5ef7193b463..dec7c9a9ab18c 100644 --- a/llvm/lib/IR/Pass.cpp +++ b/llvm/lib/IR/Pass.cpp @@ -62,8 +62,12 @@ static std::string getDescription(const Module &M) { bool ModulePass::skipModule(const Module &M) const { const OptPassGate &Gate = M.getContext().getOptPassGate(); - return Gate.isEnabled() && - !Gate.shouldRunPass(this->getPassName(), getDescription(M)); + + StringRef PassName = getPassArgument(); + if (PassName.empty()) + PassName = this->getPassName(); + + return Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(M)); } bool Pass::mustPreserveAnalysisID(char &AID) const { @@ -86,6 +90,16 @@ StringRef Pass::getPassName() const { return "Unnamed pass: implement Pass::getPassName()"; } +/// getPassArgument - Return a nice clean name for a pass +/// corresponding to that used to enable the pass in opt +StringRef Pass::getPassArgument() const { + AnalysisID AID = getPassID(); + const PassInfo *PI = Pass::lookupPassInfo(AID); + if (PI) + return PI->getPassArgument(); + return ""; +} + void Pass::preparePassManager(PMStack &) { // By default, don't do anything. } @@ -173,8 +187,12 @@ static std::string getDescription(const Function &F) { bool FunctionPass::skipFunction(const Function &F) const { OptPassGate &Gate = F.getContext().getOptPassGate(); - if (Gate.isEnabled() && - !Gate.shouldRunPass(this->getPassName(), getDescription(F))) + + StringRef PassName = getPassArgument(); + if (PassName.empty()) + PassName = this->getPassName(); + + if (Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(F))) return true; if (F.hasOptNone()) { diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp index 0623e66772047..f165e85baf611 100644 --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -1078,9 +1078,13 @@ void OptPassGateInstrumentation::registerCallbacks( if (!PassGate.isEnabled()) return; - PIC.registerShouldRunOptionalPassCallback([this](StringRef PassName, Any IR) { - return this->shouldRun(PassName, IR); - }); + PIC.registerShouldRunOptionalPassCallback( + [this, &PIC](StringRef ClassName, Any IR) { + StringRef PassName = PIC.getPassNameForClassName(ClassName); + if (PassName.empty()) + return this->shouldRun(ClassName, IR); + return this->shouldRun(PassName, IR); + }); } raw_ostream &PrintPassInstrumentation::print() { diff --git a/llvm/test/Other/opt-bisect-new-pass-manager.ll b/llvm/test/Other/opt-bisect-new-pass-manager.ll index 01dad705ec362..8f8078d4d8409 100644 --- a/llvm/test/Other/opt-bisect-new-pass-manager.ll +++ b/llvm/test/Other/opt-bisect-new-pass-manager.ll @@ -11,84 +11,84 @@ ; RUN: opt -disable-output -disable-verify \ ; RUN: -passes=inferattrs -opt-bisect-limit=-1 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-MODULE-PASS -; CHECK-MODULE-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module] +; CHECK-MODULE-PASS: BISECT: running pass (1) inferattrs on [module] ; RUN: opt -disable-output -disable-verify \ ; RUN: -passes=inferattrs -opt-bisect-limit=0 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-MODULE-PASS -; CHECK-LIMIT-MODULE-PASS: BISECT: NOT running pass (1) InferFunctionAttrsPass on [module] +; CHECK-LIMIT-MODULE-PASS: BISECT: NOT running pass (1) inferattrs on [module] ; RUN: opt -disable-output -debug-pass-manager \ ; RUN: -passes=inferattrs -opt-bisect-limit=-1 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-REQUIRED-PASS -; CHECK-REQUIRED-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module] +; CHECK-REQUIRED-PASS: BISECT: running pass (1) inferattrs on [module] ; CHECK-REQUIRED-PASS-NOT: BISECT: {{.*}}VerifierPass ; CHECK-REQUIRED-PASS: Running pass: VerifierPass ; RUN: opt -disable-output -debug-pass-manager \ ; RUN: -passes=inferattrs -opt-bisect-limit=0 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-REQUIRED-PASS -; CHECK-LIMIT-REQUIRED-PASS: BISECT: NOT running pass (1) InferFunctionAttrsPass on [module] +; CHECK-LIMIT-REQUIRED-PASS: BISECT: NOT running pass (1) inferattrs on [module] ; CHECK-LIMIT-REQUIRED-PASS-NOT: BISECT: {{.*}}VerifierPass ; CHECK-LIMIT-REQUIRED-PASS: Running pass: VerifierPass ; RUN: opt -disable-output -disable-verify \ ; RUN: -passes=early-cse -opt-bisect-limit=-1 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-FUNCTION-PASS -; CHECK-FUNCTION-PASS: BISECT: running pass (1) EarlyCSEPass on f1 -; CHECK-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on f2 -; CHECK-FUNCTION-PASS: BISECT: running pass (3) EarlyCSEPass on f3 -; CHECK-FUNCTION-PASS: BISECT: running pass (4) EarlyCSEPass on f4 +; CHECK-FUNCTION-PASS: BISECT: running pass (1) early-cse on f1 +; CHECK-FUNCTION-PASS: BISECT: running pass (2) early-cse on f2 +; CHECK-FUNCTION-PASS: BISECT: running pass (3) early-cse on f3 +; CHECK-FUNCTION-PASS: BISECT: running pass (4) early-cse on f4 ; RUN: opt -disable-output -disable-verify \ ; RUN: -passes=early-cse -opt-bisect-limit=2 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-FUNCTION-PASS -; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (1) EarlyCSEPass on f1 -; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on f2 -; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (3) EarlyCSEPass on f3 -; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (4) EarlyCSEPass on f4 +; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (1) early-cse on f1 +; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (2) early-cse on f2 +; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (3) early-cse on f3 +; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (4) early-cse on f4 ; RUN: opt -disable-output -disable-verify \ ; RUN: -passes=function-attrs -opt-bisect-limit=-1 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-CGSCC-PASS -; CHECK-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on (f1) -; CHECK-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f2) -; CHECK-CGSCC-PASS: BISECT: running pass (3) PostOrderFunctionAttrsPass on (f3) -; CHECK-CGSCC-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on (f4) +; CHECK-CGSCC-PASS: BISECT: running pass (1) function-attrs on (f1) +; CHECK-CGSCC-PASS: BISECT: running pass (2) function-attrs on (f2) +; CHECK-CGSCC-PASS: BISECT: running pass (3) function-attrs on (f3) +; CHECK-CGSCC-PASS: BISECT: running pass (4) function-attrs on (f4) ; RUN: opt -disable-output -disable-verify \ ; RUN: -passes=function-attrs -opt-bisect-limit=3 %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-CGSCC-PASS -; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on (f1) -; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f2) -; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (3) PostOrderFunctionAttrsPass on (f3) -; CHECK-LIMIT-CGSCC-PASS: BISECT: NOT running pass (4) PostOrderFunctionAttrsPass on (f4) +; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (1) function-attrs on (f1) +; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (2) function-attrs on (f2) +; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (3) function-attrs on (f3) +; CHECK-LIMIT-CGSCC-PASS: BISECT: NOT running pass (4) function-attrs on (f4) ; RUN: opt -disable-output -disable-verify -opt-bisect-limit=-1 \ ; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-MULTI-PASS -; CHECK-MULTI-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module] -; CHECK-MULTI-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f1) -; CHECK-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on f1 -; CHECK-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on (f2) -; CHECK-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on f2 -; CHECK-MULTI-PASS: BISECT: running pass (6) PostOrderFunctionAttrsPass on (f3) -; CHECK-MULTI-PASS: BISECT: running pass (7) EarlyCSEPass on f3 -; CHECK-MULTI-PASS: BISECT: running pass (8) PostOrderFunctionAttrsPass on (f4) -; CHECK-MULTI-PASS: BISECT: running pass (9) EarlyCSEPass on f4 +; CHECK-MULTI-PASS: BISECT: running pass (1) inferattrs on [module] +; CHECK-MULTI-PASS: BISECT: running pass (2) function-attrs on (f1) +; CHECK-MULTI-PASS: BISECT: running pass (3) early-cse on f1 +; CHECK-MULTI-PASS: BISECT: running pass (4) function-attrs on (f2) +; CHECK-MULTI-PASS: BISECT: running pass (5) early-cse on f2 +; CHECK-MULTI-PASS: BISECT: running pass (6) function-attrs on (f3) +; CHECK-MULTI-PASS: BISECT: running pass (7) early-cse on f3 +; CHECK-MULTI-PASS: BISECT: running pass (8) function-attrs on (f4) +; CHECK-MULTI-PASS: BISECT: running pass (9) early-cse on f4 ; RUN: opt -disable-output -disable-verify -opt-bisect-limit=7 \ ; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-MULTI-PASS -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (1) InferFunctionAttrsPass on [module] -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on (f1) -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on f1 -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on (f2) -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on f2 -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (6) PostOrderFunctionAttrsPass on (f3) -; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (7) EarlyCSEPass on f3 -; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (8) PostOrderFunctionAttrsPass on (f4) -; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (9) EarlyCSEPass on f4 +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (1) inferattrs on [module] +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (2) function-attrs on (f1) +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (3) early-cse on f1 +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (4) function-attrs on (f2) +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (5) early-cse on f2 +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (6) function-attrs on (f3) +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (7) early-cse on f3 +; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (8) function-attrs on (f4) +; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (9) early-cse on f4 ; Make sure we don't skip writing the output to stdout. ; RUN: opt %s -opt-bisect-limit=0 -passes=early-cse | opt -S | FileCheck %s -check-prefix=CHECK-OUTPUT diff --git a/llvm/test/Other/opt-disable.ll b/llvm/test/Other/opt-disable.ll new file mode 100644 index 0000000000000..4506042215cbf --- /dev/null +++ b/llvm/test/Other/opt-disable.ll @@ -0,0 +1,91 @@ +; This test uses the same IR functions of the opt-bisect test +; but it checks the correctness of the -opt-disable flag. +; -opt-disable-enable-verbosity is required to have output. + +; RUN: opt -disable-output -disable-verify \ +; RUN: -opt-disable-enable-verbosity \ +; RUN: -passes=inferattrs -opt-disable=inferattrs %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-MODULE-PASS +; CHECK-MODULE-PASS: OptDisable: NOT running pass inferattrs on [module] + +; RUN: opt -disable-output -disable-verify \ +; RUN: -opt-disable-enable-verbosity \ +; RUN: -passes=sroa -opt-disable=sroa %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-FUNCTION-PASS +; CHECK-FUNCTION-PASS: OptDisable: NOT running pass sroa on f1 +; CHECK-FUNCTION-PASS: OptDisable: NOT running pass sroa on f2 +; CHECK-FUNCTION-PASS: OptDisable: NOT running pass sroa on f3 +; CHECK-FUNCTION-PASS: OptDisable: NOT running pass sroa on f4 + +; RUN: opt -disable-output -disable-verify \ +; RUN: -opt-disable=inferattrs,function-attrs \ +; RUN: -opt-disable-enable-verbosity \ +; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-MULTI-PASS +; CHECK-MULTI-PASS: OptDisable: NOT running pass inferattrs on [module] +; CHECK-MULTI-PASS: OptDisable: NOT running pass function-attrs on (f1) +; CHECK-MULTI-PASS: OptDisable: running pass early-cse on f1 +; CHECK-MULTI-PASS: OptDisable: NOT running pass function-attrs on (f2) +; CHECK-MULTI-PASS: OptDisable: running pass early-cse on f2 +; CHECK-MULTI-PASS: OptDisable: NOT running pass function-attrs on (f3) +; CHECK-MULTI-PASS: OptDisable: running pass early-cse on f3 +; CHECK-MULTI-PASS: OptDisable: NOT running pass function-attrs on (f4) +; CHECK-MULTI-PASS: OptDisable: running pass early-cse on f4 + +declare i32 @g() + +define void @f1(i1 %arg) { +entry: + br label %loop.0 +loop.0: + br i1 %arg, label %loop.0.0, label %loop.1 +loop.0.0: + br i1 %arg, label %loop.0.0, label %loop.0.1 +loop.0.1: + br i1 %arg, label %loop.0.1, label %loop.0 +loop.1: + br i1 %arg, label %loop.1, label %loop.1.bb1 +loop.1.bb1: + br i1 %arg, label %loop.1, label %loop.1.bb2 +loop.1.bb2: + br i1 %arg, label %end, label %loop.1.0 +loop.1.0: + br i1 %arg, 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 +} + +define void @f4(i1 %arg) { +entry: + %i = alloca i32, align 4 + call void @llvm.lifetime.start(i64 4, ptr %i) + br label %for.cond + +for.cond: + br i1 %arg, label %for.body, label %for.end + +for.body: + br label %for.cond + +for.end: + ret void +} + +declare void @llvm.lifetime.start(i64, ptr nocapture)