diff options
98 files changed, 909 insertions, 79 deletions
diff --git a/include/llvm/Analysis/CallGraphSCCPass.h b/include/llvm/Analysis/CallGraphSCCPass.h index 9c7f7bd34cc..fd9ea56385d 100644 --- a/include/llvm/Analysis/CallGraphSCCPass.h +++ b/include/llvm/Analysis/CallGraphSCCPass.h @@ -77,15 +77,21 @@ public: /// the call graph. If the derived class implements this method, it should /// always explicitly call the implementation here. void getAnalysisUsage(AnalysisUsage &Info) const override; + +protected: + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when optimization bisect is over the limit. + bool skipSCC(CallGraphSCC &SCC) const; }; /// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on. class CallGraphSCC { + const CallGraph &CG; // The call graph for this SCC. void *Context; // The CGPassManager object that is vending this. std::vector<CallGraphNode*> Nodes; public: - CallGraphSCC(void *context) : Context(context) {} + CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {} void initialize(CallGraphNode *const *I, CallGraphNode *const *E) { Nodes.assign(I, E); @@ -101,6 +107,8 @@ public: typedef std::vector<CallGraphNode *>::const_iterator iterator; iterator begin() const { return Nodes.begin(); } iterator end() const { return Nodes.end(); } + + const CallGraph &getCallGraph() { return CG; } }; } // End llvm namespace diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h index 4e72052b9b8..b3e919d1626 100644 --- a/include/llvm/Analysis/LazyCallGraph.h +++ b/include/llvm/Analysis/LazyCallGraph.h @@ -923,6 +923,15 @@ public: PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +/// Check with the OptBisect object to determine whether the described pass +/// should be skipped. +/// +/// This is a helper function which abstracts the details of accessing OptBisect +/// through an LLVMContext obtained from an SCC. +bool skipPassForSCC(const StringRef PassName, const LazyCallGraph::SCC &SCC); +// This function is implemented in OptBisect.cpp but must be declared +// here to avoid include file dependency problems. + } #endif diff --git a/include/llvm/Analysis/LoopPass.h b/include/llvm/Analysis/LoopPass.h index 2cf734e53bb..89debec04e9 100644 --- a/include/llvm/Analysis/LoopPass.h +++ b/include/llvm/Analysis/LoopPass.h @@ -88,9 +88,10 @@ public: virtual void deleteAnalysisLoop(Loop *L) {} protected: - /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const Loop *L) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipLoop(const Loop *L) const; }; class LPPassManager : public FunctionPass, public PMDataManager { diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index 1d05269ab73..8f13171f962 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -32,6 +32,7 @@ class DiagnosticInfo; template <typename T> class SmallVectorImpl; class Function; class DebugLoc; +class OptBisect; /// This is an important class for using LLVM in a threaded context. It /// (opaquely) owns and manages the core "global" data of LLVM's core @@ -226,6 +227,9 @@ public: return OptionRegistry::instance().template get<ValT, Base, Mem>(); } + /// \brief Access the object which manages optimization bisection for failure + /// analysis. + OptBisect &getOptBisect(); private: LLVMContext(LLVMContext&) = delete; void operator=(LLVMContext&) = delete; diff --git a/include/llvm/IR/OptBisect.h b/include/llvm/IR/OptBisect.h new file mode 100644 index 00000000000..d4c8fcf9a44 --- /dev/null +++ b/include/llvm/IR/OptBisect.h @@ -0,0 +1,139 @@ +//===----------- llvm/IR/OptBisect.h - LLVM Bisect support -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the interface for bisecting optimizations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_OPTBISECT_H +#define LLVM_IR_OPTBISECT_H + +namespace llvm { + +class Pass; +class StringRef; +class Twine; + +/// 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 +/// optimization-related problems. +class OptBisect { +public: + /// \brief Default constructor, initializes the OptBisect state based on the + /// -opt-bisect-limit command line argument. + /// + /// By default, bisection is disabled. + /// + /// Clients should not instantiate this class directly. All access should go + /// through LLVMContext. + OptBisect(); + + /// Checks the bisect limit to determine if the specified pass should run. + /// + /// This function will immediate return true if bisection is disabled. If the + /// bisect limit is set to -1, the function will print a message describing + /// the pass and the bisect number assigned to it and return true. Otherwise, + /// the function will print a message with the bisect number assigned to the + /// pass and indicating whether or not the pass will be run and return true if + /// the bisect limit has not yet been exceded or false if it has. + /// + /// Most passes should not call this routine directly. Instead, it is called + /// through a helper routine provided by the pass base class. For instance, + /// function passes should call FunctionPass::skipFunction(). + template <class UnitT> + bool shouldRunPass(const Pass *P, const UnitT &U); + + /// Checks the bisect limit to determine if the specified pass should run. + /// + /// This function will immediate return true if bisection is disabled. If the + /// bisect limit is set to -1, the function will print a message describing + /// the pass and the bisect number assigned to it and return true. Otherwise, + /// the function will print a message with the bisect number assigned to the + /// pass and indicating whether or not the pass will be run and return true if + /// the bisect limit has not yet been exceded or false if it has. + /// + /// In order to avoid duplicating the code necessary to access OptBisect + /// through the LLVMContext class, passes may call one of the helper + /// functions that get the context from an IR object. For instance, + /// function passes may call skipPassForFunction(). + template <class UnitT> + bool shouldRunPass(const StringRef PassName, const UnitT &U); + + /// Checks the bisect limit to determine if the optimization described by the + /// /p Desc argument should run. + /// + /// This function will immediate return true if bisection is disabled. If the + /// bisect limit is set to -1, the function will print a message with the + /// bisect number assigned to the optimization along with the /p Desc + /// description and return true. Otherwise, the function will print a message + /// with the bisect number assigned to the optimization and indicating whether + /// or not the pass will be run and return true if the bisect limit has not + /// yet been exceded or false if it has. + /// + /// Passes may call this function to provide more fine grained control over + /// individual optimizations performed by the pass. Passes which cannot be + /// skipped entirely (such as non-optional code generation passes) may still + /// call this function to control whether or not individual optional + /// transformations are performed. + bool shouldRunCase(const Twine &Desc); + +private: + bool checkPass(const StringRef PassName, const StringRef TargetDesc); + + bool BisectEnabled = false; + unsigned LastBisectNum = 0; +}; + +// Access to OptBisect should go through LLVMContext, but for the +// new pass manager there is no single base class from which a +// helper function to abstract the messy details can be provided. +// Instead, we provide standalone helper functions for each IR +// type that must be handled. + +class Module; +class Function; +//class BasicBlock; +//class Loop; + +/// Check with the OptBisect object to determine whether the described pass +/// should be skipped. +/// +/// This is a helper function which abstracts the details of accessing OptBisect +/// through an LLVMContext obtained from a Module. +bool skipPassForModule(const StringRef PassName, const Module &M); + +/// Check with the OptBisect object to determine whether the described pass +/// should be skipped. +/// +/// This is a helper function which abstracts the details of accessing OptBisect +/// through an LLVMContext obtained from a Function. +bool skipPassForFunction(const StringRef PassName, const Function &F); +#if 0 +/// Check with the OptBisect object to determine whether the described pass +/// should be skipped. +/// +/// This is a helper function which abstracts the details of accessing OptBisect +/// through an LLVMContext obtained from a BasicBlock. +bool skipPassForBasicBlock(const StringRef PassName, const BasicBlock &BB); + +/// Check with the OptBisect object to determine whether the described pass +/// should be skipped. +/// +/// This is a helper function which abstracts the details of accessing OptBisect +/// through an LLVMContext obtained from a Loop. +bool skipPassForLoop(const StringRef PassName, const Loop &L); +#endif +// skiPassForSCC is declared in LazyCallGraph.h because of include file +// dependency issues related to LazyCallGraph::SCC being nested. + +} // end namespace llvm + +#endif // LLVM_IR_OPTBISECT_H diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index 99604cdbc9c..7fcdcbc22bc 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -251,6 +251,11 @@ public: explicit ModulePass(char &pid) : Pass(PT_Module, pid) {} // Force out-of-line virtual method. ~ModulePass() override; + +protected: + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when optimization bisect is over the limit. + bool skipModule(Module &M) const; }; @@ -310,9 +315,10 @@ public: PassManagerType getPotentialPassManagerType() const override; protected: - /// skipOptnoneFunction - This function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const Function &F) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipFunction(const Function &F) const; }; @@ -359,9 +365,10 @@ public: PassManagerType getPotentialPassManagerType() const override; protected: - /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const BasicBlock &BB) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipBasicBlock(const BasicBlock &BB) const; }; /// If the user specifies the -time-passes argument on an LLVM tool command line diff --git a/lib/Analysis/CallGraphSCCPass.cpp b/lib/Analysis/CallGraphSCCPass.cpp index 6dd1d0a066b..71226bd25ca 100644 --- a/lib/Analysis/CallGraphSCCPass.cpp +++ b/lib/Analysis/CallGraphSCCPass.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManagers.h" +#include "llvm/IR/OptBisect.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Timer.h" @@ -444,7 +445,7 @@ bool CGPassManager::runOnModule(Module &M) { // Walk the callgraph in bottom-up SCC order. scc_iterator<CallGraph*> CGI = scc_begin(&CG); - CallGraphSCC CurSCC(&CGI); + CallGraphSCC CurSCC(CG, &CGI); while (!CGI.isAtEnd()) { // Copy the current SCC and increment past it so that the pass can hack // on the SCC if it wants to without invalidating our iterator. @@ -631,3 +632,9 @@ Pass *CallGraphSCCPass::createPrinterPass(raw_ostream &O, return new PrintCallGraphPass(Banner, O); } +bool CallGraphSCCPass::skipSCC(CallGraphSCC &SCC) const { + return !SCC.getCallGraph().getModule() + .getContext() + .getOptBisect() + .shouldRunPass(this, SCC); +} diff --git a/lib/Analysis/LoopPass.cpp b/lib/Analysis/LoopPass.cpp index 8163231c332..3181e4f9921 100644 --- a/lib/Analysis/LoopPass.cpp +++ b/lib/Analysis/LoopPass.cpp @@ -16,6 +16,7 @@ #include "llvm/Analysis/LoopPass.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/OptBisect.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Timer.h" @@ -335,11 +336,16 @@ void LoopPass::assignPassManager(PMStack &PMS, LPPM->add(this); } -// Containing function has Attribute::OptimizeNone and transformation -// passes should skip it. -bool LoopPass::skipOptnoneFunction(const Loop *L) const { +bool LoopPass::skipLoop(const Loop *L) const { const Function *F = L->getHeader()->getParent(); - if (F && F->hasFnAttribute(Attribute::OptimizeNone)) { + if (!F) + return false; + // Check the opt bisect limit. + LLVMContext &Context = F->getContext(); + if (!Context.getOptBisect().shouldRunPass(this, *L)) + return true; + // Check for the OptimizeNone attribute. + if (F->hasFnAttribute(Attribute::OptimizeNone)) { // FIXME: Report this to dbgs() only once per function. DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' in function " << F->getName() << "\n"); diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp index 065bac015c5..d0b23044566 100644 --- a/lib/CodeGen/BranchFolding.cpp +++ b/lib/CodeGen/BranchFolding.cpp @@ -90,7 +90,7 @@ INITIALIZE_PASS(BranchFolderPass, "branch-folder", "Control Flow Optimizer", false, false) bool BranchFolderPass::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; TargetPassConfig *PassConfig = &getAnalysis<TargetPassConfig>(); diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp index ea1325a8627..e34233a5c15 100644 --- a/lib/CodeGen/CodeGenPrepare.cpp +++ b/lib/CodeGen/CodeGenPrepare.cpp @@ -211,7 +211,7 @@ FunctionPass *llvm::createCodeGenPreparePass(const TargetMachine *TM) { } bool CodeGenPrepare::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; DL = &F.getParent()->getDataLayout(); diff --git a/lib/CodeGen/DeadMachineInstructionElim.cpp b/lib/CodeGen/DeadMachineInstructionElim.cpp index b11b49717c4..ae58b5bb0e7 100644 --- a/lib/CodeGen/DeadMachineInstructionElim.cpp +++ b/lib/CodeGen/DeadMachineInstructionElim.cpp @@ -90,7 +90,7 @@ bool DeadMachineInstructionElim::isDead(const MachineInstr *MI) const { } bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; bool AnyChanges = false; diff --git a/lib/CodeGen/LowerEmuTLS.cpp b/lib/CodeGen/LowerEmuTLS.cpp index 0b9a501e395..6966c8ca4a5 100644 --- a/lib/CodeGen/LowerEmuTLS.cpp +++ b/lib/CodeGen/LowerEmuTLS.cpp @@ -63,6 +63,9 @@ ModulePass *llvm::createLowerEmuTLSPass(const TargetMachine *TM) { } bool LowerEmuTLS::runOnModule(Module &M) { + if (skipModule(M)) + return false; + if (!TM || !TM->Options.EmulatedTLS) return false; diff --git a/lib/CodeGen/MachineBlockPlacement.cpp b/lib/CodeGen/MachineBlockPlacement.cpp index af78d8a8924..6a9078a78f5 100644 --- a/lib/CodeGen/MachineBlockPlacement.cpp +++ b/lib/CodeGen/MachineBlockPlacement.cpp @@ -1430,7 +1430,7 @@ bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &F) { if (std::next(F.begin()) == F.end()) return false; - if (skipOptnoneFunction(*F.getFunction())) + if (skipFunction(*F.getFunction())) return false; MBPI = &getAnalysis<MachineBranchProbabilityInfo>(); diff --git a/lib/CodeGen/MachineCSE.cpp b/lib/CodeGen/MachineCSE.cpp index c602b51f2a6..b8283eaf9e2 100644 --- a/lib/CodeGen/MachineCSE.cpp +++ b/lib/CodeGen/MachineCSE.cpp @@ -704,7 +704,7 @@ bool MachineCSE::PerformCSE(MachineDomTreeNode *Node) { } bool MachineCSE::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; TII = MF.getSubtarget().getInstrInfo(); diff --git a/lib/CodeGen/MachineCopyPropagation.cpp b/lib/CodeGen/MachineCopyPropagation.cpp index 3fdf16fb630..7f2e7784026 100644 --- a/lib/CodeGen/MachineCopyPropagation.cpp +++ b/lib/CodeGen/MachineCopyPropagation.cpp @@ -349,7 +349,7 @@ void MachineCopyPropagation::CopyPropagateBlock(MachineBasicBlock &MBB) { } bool MachineCopyPropagation::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; Changed = false; diff --git a/lib/CodeGen/MachineLICM.cpp b/lib/CodeGen/MachineLICM.cpp index 99a97d2dbd7..7d0221fdc46 100644 --- a/lib/CodeGen/MachineLICM.cpp +++ b/lib/CodeGen/MachineLICM.cpp @@ -260,7 +260,7 @@ static bool LoopIsOuterMostWithPredecessor(MachineLoop *CurLoop) { } bool MachineLICM::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; Changed = FirstInLoop = false; diff --git a/lib/CodeGen/MachineScheduler.cpp b/lib/CodeGen/MachineScheduler.cpp index e4d1c3c3c92..9e28ed93732 100644 --- a/lib/CodeGen/MachineScheduler.cpp +++ b/lib/CodeGen/MachineScheduler.cpp @@ -319,7 +319,7 @@ ScheduleDAGInstrs *PostMachineScheduler::createPostMachineScheduler() { /// design would be to split blocks at scheduling boundaries, but LLVM has a /// general bias against block splitting purely for implementation simplicity. bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) { - if (skipOptnoneFunction(*mf.getFunction())) + if (skipFunction(*mf.getFunction())) return false; if (EnableMachineSched.getNumOccurrences()) { @@ -357,7 +357,7 @@ bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) { } bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) { - if (skipOptnoneFunction(*mf.getFunction())) + if (skipFunction(*mf.getFunction())) return false; if (EnablePostRAMachineSched.getNumOccurrences()) { diff --git a/lib/CodeGen/MachineSink.cpp b/lib/CodeGen/MachineSink.cpp index 07fbd3d36ab..c42281b1455 100644 --- a/lib/CodeGen/MachineSink.cpp +++ b/lib/CodeGen/MachineSink.cpp @@ -257,7 +257,7 @@ MachineSinking::AllUsesDominatedByBlock(unsigned Reg, } bool MachineSinking::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; DEBUG(dbgs() << "******** Machine Sinking ********\n"); diff --git a/lib/CodeGen/OptimizePHIs.cpp b/lib/CodeGen/OptimizePHIs.cpp index a1042e720c3..0177e414f8d 100644 --- a/lib/CodeGen/OptimizePHIs.cpp +++ b/lib/CodeGen/OptimizePHIs.cpp @@ -63,7 +63,7 @@ INITIALIZE_PASS(OptimizePHIs, "opt-phis", "Optimize machine instruction PHIs", false, false) bool OptimizePHIs::runOnMachineFunction(MachineFunction &Fn) { - if (skipOptnoneFunction(*Fn.getFunction())) + if (skipFunction(*Fn.getFunction())) return false; MRI = &Fn.getRegInfo(); diff --git a/lib/CodeGen/PeepholeOptimizer.cpp b/lib/CodeGen/PeepholeOptimizer.cpp index 52b42b624ee..35561506b8d 100644 --- a/lib/CodeGen/PeepholeOptimizer.cpp +++ b/lib/CodeGen/PeepholeOptimizer.cpp @@ -1471,7 +1471,7 @@ bool PeepholeOptimizer::foldRedundantNAPhysCopy( } bool PeepholeOptimizer::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; DEBUG(dbgs() << "********** PEEPHOLE OPTIMIZER **********\n"); diff --git a/lib/CodeGen/PostRASchedulerList.cpp b/lib/CodeGen/PostRASchedulerList.cpp index ad9f94609b8..79958c9a8b3 100644 --- a/lib/CodeGen/PostRASchedulerList.cpp +++ b/lib/CodeGen/PostRASchedulerList.cpp @@ -273,7 +273,7 @@ bool PostRAScheduler::enablePostRAScheduler( } bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { - if (skipOptnoneFunction(*Fn.getFunction())) + if (skipFunction(*Fn.getFunction())) return false; TII = Fn.getSubtarget().getInstrInfo(); diff --git a/lib/CodeGen/StackColoring.cpp b/lib/CodeGen/StackColoring.cpp index d7ad48e49ff..d93fc6aff36 100644 --- a/lib/CodeGen/StackColoring.cpp +++ b/lib/CodeGen/StackColoring.cpp @@ -657,7 +657,7 @@ void StackColoring::expungeSlotMap(DenseMap<int, int> &SlotRemap, } bool StackColoring::runOnMachineFunction(MachineFunction &Func) { - if (skipOptnoneFunction(*Func.getFunction())) + if (skipFunction(*Func.getFunction())) return false; DEBUG(dbgs() << "********** Stack Coloring **********\n" diff --git a/lib/CodeGen/TailDuplication.cpp b/lib/CodeGen/TailDuplication.cpp index 4831c6a86c2..2b1fb127497 100644 --- a/lib/CodeGen/TailDuplication.cpp +++ b/lib/CodeGen/TailDuplication.cpp @@ -44,7 +44,7 @@ INITIALIZE_PASS(TailDuplicatePass, "tailduplication", "Tail Duplication", false, false) bool TailDuplicatePass::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; auto MMI = getAnalysisIfAvailable<MachineModuleInfo>(); diff --git a/lib/IR/CMakeLists.txt b/lib/IR/CMakeLists.txt index 554ea1422a1..f3f87338ca4 100644 --- a/lib/IR/CMakeLists.txt +++ b/lib/IR/CMakeLists.txt @@ -39,6 +39,7 @@ add_llvm_library(LLVMCore Module.cpp ModuleSummaryIndex.cpp Operator.cpp + OptBisect.cpp Pass.cpp PassManager.cpp PassRegistry.cpp diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp index 45c28061b0c..ee95c4f80e4 100644 --- a/lib/IR/LLVMContext.cpp +++ b/lib/IR/LLVMContext.cpp @@ -325,3 +325,7 @@ void LLVMContext::disableDebugTypeODRUniquing() { pImpl->DITypeMap.reset(); } void LLVMContext::setDiscardValueNames(bool Discard) { pImpl->DiscardValueNames = Discard; } + +OptBisect &LLVMContext::getOptBisect() { + return pImpl->getOptBisect(); +} diff --git a/lib/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp index d5d9038d1e9..d27fcb1f2e7 100644 --- a/lib/IR/LLVMContextImpl.cpp +++ b/lib/IR/LLVMContextImpl.cpp @@ -16,6 +16,8 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Module.h" +#include "llvm/IR/OptBisect.h" +#include "llvm/Support/ManagedStatic.h" #include <algorithm> using namespace llvm; @@ -232,3 +234,19 @@ void GetElementPtrConstantExpr::anchor() { } void CompareConstantExpr::anchor() { } +/// Singleton instance of the OptBisect class. +/// +/// This singleton is accessed via the LLVMContext::getOptBisect() function. It +/// provides 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 optimization-related problems. +/// +/// Even if multiple LLVMContext objects are created, they will all return the +/// same instance of OptBisect in order to provide a single bisect count. Any +/// code that uses the OptBisect object should be serialized when bisection is +/// enabled in order to enable a consistent bisect count. +static ManagedStatic<OptBisect> OptBisector; + +OptBisect &LLVMContextImpl::getOptBisect() { + return *OptBisector; +} diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index 0d6d9799b46..a4d7b7eaf9e 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -1133,6 +1133,10 @@ public: /// Destroy the ConstantArrays if they are not used. void dropTriviallyDeadConstantArrays(); + + /// \brief Access the object which manages optimization bisection for failure + /// analysis. + OptBisect &getOptBisect(); }; } diff --git a/lib/IR/OptBisect.cpp b/lib/IR/OptBisect.cpp new file mode 100644 index 00000000000..d06f40fce35 --- /dev/null +++ b/lib/IR/OptBisect.cpp @@ -0,0 +1,176 @@ +//===------- llvm/IR/OptBisect/Bisect.cpp - LLVM Bisect support --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements support for a bisecting optimizations based on a +/// command line option. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OptBisect.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden, + cl::init(INT_MAX), cl::Optional, + cl::desc("Maximum optimization to perform")); + +OptBisect::OptBisect() { + BisectEnabled = OptBisectLimit != INT_MAX; +} + +static void printPassMessage(const StringRef &Name, int PassNum, + StringRef TargetDesc, bool Running) { + StringRef Status = Running ? "" : "NOT "; + errs() << "BISECT: " << Status << "running pass " + << "(" << PassNum << ") " << Name << " on " << TargetDesc << "\n"; +} + +static void printCaseMessage(int CaseNum, StringRef Msg, bool Running) { + if (Running) + errs() << "BISECT: running case ("; + else + errs() << "BISECT: NOT running case ("; + errs() << CaseNum << "): " << Msg << "\n"; +} + +static std::string getDescription(const Module &M) { + return "module (" + M.getName().str() + ")"; +} + +static std::string getDescription(const Function &F) { + return "function (" + F.getName().str() + ")"; +} + +static std::string getDescription(const BasicBlock &BB) { + return "basic block (" + BB.getName().str() + ") in function (" + + BB.getParent()->getName().str() + ")"; +} + +static std::string getDescription(const Loop &L) { + // FIXME: I'd like to be able to provide a better description here, but + // calling L->getHeader() would introduce a new dependency on the + // LLVMCore library. + return "loop"; +} + +static std::string getDescription(const CallGraphSCC &SCC) { + std::string Desc = "SCC ("; + bool First = true; + for (CallGraphNode *CGN : SCC) { + if (First) + First = false; + else + Desc += ", "; + Function *F = CGN->getFunction(); + if (F) + Desc += F->getName(); + else + Desc += "<<null function>>"; + } + Desc += ")"; + return Desc; +} + +static std::string getDescription(const LazyCallGraph::SCC &SCC) { + std::string Desc = "SCC ("; + bool First = true; + for (LazyCallGraph::Node &CGN : SCC) { + if (First) + First = false; + else + Desc += ", "; + Function &F = CGN.getFunction(); + Desc += F.getName(); + } + Desc += ")"; + return Desc; +} + +// Force instantiations. +template bool OptBisect::shouldRunPass(const Pass *, const Module &); +template bool OptBisect::shouldRunPass(const Pass *, const Function &); +template bool OptBisect::shouldRunPass(const Pass *, const BasicBlock &); +template bool OptBisect::shouldRunPass(const Pass *, const Loop &); +template bool OptBisect::shouldRunPass(const Pass *, const CallGraphSCC &); +template bool OptBisect::shouldRunPass(const StringRef PassName, + const Module &); +template bool OptBisect::shouldRunPass(const StringRef PassName, + const Function &); +template bool OptBisect::shouldRunPass(const StringRef PassName, + const BasicBlock &); +template bool OptBisect::shouldRunPass(const StringRef PassName, const Loop &); +template bool OptBisect::shouldRunPass(const StringRef PassName, + const LazyCallGraph::SCC &); + +template <class UnitT> +bool OptBisect::shouldRunPass(const Pass *P, const UnitT &U) { + if (!BisectEnabled) + return true; + return checkPass(P->getPassName(), getDescription(U)); +} + +// Interface function for the new pass manager. +template <class UnitT> +bool OptBisect::shouldRunPass(const StringRef PassName, const UnitT &U) { + if (!BisectEnabled) + return true; + return checkPass(PassName, getDescription(U)); +} + +bool OptBisect::checkPass(const StringRef PassName, + const StringRef TargetDesc) { + assert(BisectEnabled); + + int CurBisectNum = ++LastBisectNum; + bool ShouldRun = (OptBisectLimit == -1 || CurBisectNum <= OptBisectLimit); + printPassMessage(PassName, CurBisectNum, TargetDesc, ShouldRun); + return ShouldRun; +} + +bool OptBisect::shouldRunCase(const Twine &Msg) { + if (!BisectEnabled) + return true; + int CurFuelNum = ++LastBisectNum; + bool ShouldRun = (OptBisectLimit == -1 || CurFuelNum <= OptBisectLimit); + printCaseMessage(CurFuelNum, Msg.str(), ShouldRun); + return ShouldRun; +} + +bool llvm::skipPassForModule(const StringRef PassName, const Module &M) { + return !M.getContext().getOptBisect().shouldRunPass(PassName, M); +} + +bool llvm::skipPassForFunction(const StringRef PassName, const Function &F) { + return !F.getContext().getOptBisect().shouldRunPass(PassName, F); +} +#if 0 +bool llvm::skipPassForBasicBlock(const StringRef PassName, const BasicBlock &BB) { + return !BB.getContext().getOptBisect().shouldRunPass(PassName, BB); +} + +bool llvm::skipPassForLoop(const StringRef PassName, const Loop &L) { + const Function *F = L.getHeader()->getParent(); + if (!F) + return false; + return !F->getContext().getOptBisect().shouldRunPass(PassName, L); +} +#endif +bool llvm::skipPassForSCC(const StringRef PassName, const LazyCallGraph::SCC &SCC) { + LLVMContext &Context = SCC.begin()->getFunction().getContext(); + return !Context.getOptBisect().shouldRunPass(PassName, SCC); +} + diff --git a/lib/IR/Pass.cpp b/lib/IR/Pass.cpp index 8ce65596b76..69299fea763 100644 --- a/lib/IR/Pass.cpp +++ b/lib/IR/Pass.cpp @@ -17,6 +17,8 @@ #include "llvm/IR/Function.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LegacyPassNameParser.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OptBisect.h" #include "llvm/PassRegistry.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -45,6 +47,10 @@ PassManagerType ModulePass::getPotentialPassManagerType() const { return PMT_ModulePassManager; } +bool ModulePass::skipModule(Module &M) const { + return !M.getContext().getOptBisect().shouldRunPass(this, M); +} + bool Pass::mustPreserveAnalysisID(char &AID) const { return Resolver->getAnalysisIfAvailable(&AID, true) != nullptr; } @@ -140,10 +146,13 @@ PassManagerType FunctionPass::getPotentialPassManagerType() const { return PMT_FunctionPassManager; } -bool FunctionPass::skipOptnoneFunction(const Function &F) const { +bool FunctionPass::skipFunction(const Function &F) const { + if (!F.getContext().getOptBisect().shouldRunPass(this, F)) + return true; + if (F.hasFnAttribute(Attribute::OptimizeNone)) { - DEBUG(dbgs() << "Skipping pass '" << getPassName() - << "' on function " << F.getName() << "\n"); + DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function " + << F.getName() << "\n"); return true; } return false; @@ -168,9 +177,13 @@ bool BasicBlockPass::doFinalization(Function &) { return false; } -bool BasicBlockPass::skipOptnoneFunction(const BasicBlock &BB) const { +bool BasicBlockPass::skipBasicBlock(const BasicBlock &BB) const { const Function *F = BB.getParent(); - if (F && F->hasFnAttribute(Attribute::OptimizeNone)) { + if (!F) + return false; + if (!F->getContext().getOptBisect().shouldRunPass(this, BB)) + return true; + if (F->hasFnAttribute(Attribute::OptimizeNone)) { // Report this only once per function. if (&BB == &F->getEntryBlock()) DEBUG(dbgs() << "Skipping pass '" << getPassName() diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index 1c0f5900d8d..8823b811748 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -114,6 +114,9 @@ Pass *llvm::createArgumentPromotionPass(unsigned maxElements) { } bool ArgPromotion::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + bool Changed = false, LocalChange; do { // Iterate until we stop promoting from this SCC. diff --git a/lib/Transforms/IPO/ConstantMerge.cpp b/lib/Transforms/IPO/ConstantMerge.cpp index 0aa49d6fde0..87f35fd64f0 100644 --- a/lib/Transforms/IPO/ConstantMerge.cpp +++ b/lib/Transforms/IPO/ConstantMerge.cpp @@ -96,6 +96,8 @@ unsigned ConstantMerge::getAlignment(GlobalVariable *GV) const { } bool ConstantMerge::runOnModule(Module &M) { + if (skipModule(M)) + return false; // Find all the globals that are marked "used". These cannot be merged. SmallPtrSet<const GlobalValue*, 8> UsedGlobals; diff --git a/lib/Transforms/IPO/CrossDSOCFI.cpp b/lib/Transforms/IPO/CrossDSOCFI.cpp index 9cf57dc1004..4c62cbe2da5 100644 --- a/lib/Transforms/IPO/CrossDSOCFI.cpp +++ b/lib/Transforms/IPO/CrossDSOCFI.cpp @@ -158,6 +158,9 @@ void CrossDSOCFI::buildCFICheck() { } bool CrossDSOCFI::runOnModule(Module &M) { + if (skipModule(M)) + return false; + if (M.getModuleFlag("Cross-DSO CFI") == nullptr) return false; buildCFICheck(); diff --git a/lib/Transforms/IPO/DeadArgumentElimination.cpp b/lib/Transforms/IPO/DeadArgumentElimination.cpp index 27379bed7ed..3ca5acda34c 100644 --- a/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -1092,6 +1092,9 @@ bool DAE::RemoveDeadStuffFromFunction(Function *F) { } bool DAE::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; // First pass: Do a simple check to see if any functions can have their "..." diff --git a/lib/Transforms/IPO/ElimAvailExtern.cpp b/lib/Transforms/IPO/ElimAvailExtern.cpp index af313a6b001..083debc3148 100644 --- a/lib/Transforms/IPO/ElimAvailExtern.cpp +++ b/lib/Transforms/IPO/ElimAvailExtern.cpp @@ -50,6 +50,9 @@ ModulePass *llvm::createEliminateAvailableExternallyPass() { } bool EliminateAvailableExternally::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; // Drop initializers of available externally global variables. diff --git a/lib/Transforms/IPO/ExtractGV.cpp b/lib/Transforms/IPO/ExtractGV.cpp index 23e517797ca..e1bd676373b 100644 --- a/lib/Transforms/IPO/ExtractGV.cpp +++ b/lib/Transforms/IPO/ExtractGV.cpp @@ -68,6 +68,9 @@ namespace { : ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS) {} bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + // Visit the global inline asm. if (!deleteStuff) M.setModuleInlineAsm(""); diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index ec6062a51f0..a9a2db17a63 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -987,6 +987,9 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) { PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { + if (skipPassForSCC(name(), C)) + return PreservedAnalyses::all(); + Module &M = *C.begin()->getFunction().getParent(); const ModuleAnalysisManager &MAM = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager(); @@ -1081,6 +1084,9 @@ INITIALIZE_PASS_END(PostOrderFunctionAttrsLegacyPass, "functionattrs", Pass *llvm::createPostOrderFunctionAttrsLegacyPass() { return new PostOrderFunctionAttrsLegacyPass(); } bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); bool Changed = false; @@ -1195,6 +1201,9 @@ static bool addNoRecurseAttrsTopDown(Function &F) { } bool ReversePostOrderFunctionAttrs::runOnModule(Module &M) { + if (skipModule(M)) + return false; + // We only have a post-order SCC traversal (because SCCs are inherently // discovered in post-order), so we accumulate them in a vector and then walk // it in reverse. This is simpler than using the RPO iterator infrastructure diff --git a/lib/Transforms/IPO/FunctionImport.cpp b/lib/Transforms/IPO/FunctionImport.cpp index 25d413030f4..cb8d6331d79 100644 --- a/lib/Transforms/IPO/FunctionImport.cpp +++ b/lib/Transforms/IPO/FunctionImport.cpp @@ -499,6 +499,9 @@ public: : ModulePass(ID), Index(Index) {} bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + if (SummaryFile.empty() && !Index) report_fatal_error("error: -function-import requires -summary-file or " "file from frontend\n"); diff --git a/lib/Transforms/IPO/GlobalDCE.cpp b/lib/Transforms/IPO/GlobalDCE.cpp index 531aa4d50c0..63d3032e131 100644 --- a/lib/Transforms/IPO/GlobalDCE.cpp +++ b/lib/Transforms/IPO/GlobalDCE.cpp @@ -75,6 +75,9 @@ INITIALIZE_PASS(GlobalDCE, "globaldce", ModulePass *llvm::createGlobalDCEPass() { return new GlobalDCE(); } bool GlobalDCE::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; // Remove empty functions from the global ctors list. diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 60d1e7ccbe6..a9c2a95a479 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -2528,6 +2528,9 @@ bool GlobalOpt::OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn) { } bool GlobalOpt::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; auto &DL = M.getDataLayout(); diff --git a/lib/Transforms/IPO/IPConstantPropagation.cpp b/lib/Transforms/IPO/IPConstantPropagation.cpp index 060aac19efa..a1533b3630e 100644 --- a/lib/Transforms/IPO/IPConstantPropagation.cpp +++ b/lib/Transforms/IPO/IPConstantPropagation.cpp @@ -54,6 +54,9 @@ INITIALIZE_PASS(IPCP, "ipconstprop", ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); } bool IPCP::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; bool LocalChange = true; diff --git a/lib/Transforms/IPO/InferFunctionAttrs.cpp b/lib/Transforms/IPO/InferFunctionAttrs.cpp index 030a6464522..02fc1f605ef 100644 --- a/lib/Transforms/IPO/InferFunctionAttrs.cpp +++ b/lib/Transforms/IPO/InferFunctionAttrs.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/OptBisect.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -955,6 +956,9 @@ static bool inferAllPrototypeAttributes(Module &M, PreservedAnalyses InferFunctionAttrsPass::run(Module &M, AnalysisManager<Module> &AM) { + if (skipPassForModule(name(), M)) + return PreservedAnalyses::all(); + auto &TLI = AM.getResult<TargetLibraryAnalysis>(M); if (!inferAllPrototypeAttributes(M, TLI)) @@ -979,6 +983,9 @@ struct InferFunctionAttrsLegacyPass : public ModulePass { } bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); return inferAllPrototypeAttributes(M, TLI); } diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index 2c696cc609a..d598c5f0f3c 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -356,6 +356,9 @@ static bool InlineHistoryIncludes(Function *F, int InlineHistoryID, } bool Inliner::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); ACT = &getAnalysis<AssumptionCacheTracker>(); auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); diff --git a/lib/Transforms/IPO/Internalize.cpp b/lib/Transforms/IPO/Internalize.cpp index ca868e9d224..6db826ffe62 100644 --- a/lib/Transforms/IPO/Internalize.cpp +++ b/lib/Transforms/IPO/Internalize.cpp @@ -105,6 +105,9 @@ public: } bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + CallGraphWrapperPass *CGPass = getAnalysisIfAvailable<CallGraphWrapperPass>(); CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr; diff --git a/lib/Transforms/IPO/LoopExtractor.cpp b/lib/Transforms/IPO/LoopExtractor.cpp index 3c6a7bb7a17..7578e6a6d19 100644 --- a/lib/Transforms/IPO/LoopExtractor.cpp +++ b/lib/Transforms/IPO/LoopExtractor.cpp @@ -81,7 +81,7 @@ INITIALIZE_PASS(SingleLoopExtractor, "loop-extract-single", Pass *llvm::createLoopExtractorPass() { return new LoopExtractor(); } bool LoopExtractor::runOnLoop(Loop *L, LPPassManager &) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; // Only visit top-level loops. @@ -249,6 +249,9 @@ void BlockExtractorPass::SplitLandingPadPreds(Function *F) { } bool BlockExtractorPass::runOnModule(Module &M) { + if (skipModule(M)) + return false; + std::set<BasicBlock*> TranslatedBlocksToNotExtract; for (unsigned i = 0, e = BlocksToNotExtract.size(); i != e; ++i) { BasicBlock *BB = BlocksToNotExtract[i]; diff --git a/lib/Transforms/IPO/LowerBitSets.cpp b/lib/Transforms/IPO/LowerBitSets.cpp index db5bab0cb10..78981fdedad 100644 --- a/lib/Transforms/IPO/LowerBitSets.cpp +++ b/lib/Transforms/IPO/LowerBitSets.cpp @@ -1051,6 +1051,9 @@ bool LowerBitSets::eraseBitSetMetadata() { } bool LowerBitSets::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = buildBitSets(); Changed |= eraseBitSetMetadata(); return Changed; diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp index 4e27898b570..e16749c76b8 100644 --- a/lib/Transforms/IPO/MergeFunctions.cpp +++ b/lib/Transforms/IPO/MergeFunctions.cpp @@ -1525,6 +1525,9 @@ bool MergeFunctions::doSanityCheck(std::vector<WeakVH> &Worklist) { } bool MergeFunctions::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; // All functions in the module, ordered by hash. Functions with a unique diff --git a/lib/Transforms/IPO/PartialInlining.cpp b/lib/Transforms/IPO/PartialInlining.cpp index 0c5c84bbcca..7b1b0985043 100644 --- a/lib/Transforms/IPO/PartialInlining.cpp +++ b/lib/Transforms/IPO/PartialInlining.cpp @@ -149,6 +149,9 @@ Function* PartialInliner::unswitchFunction(Function* F) { } bool PartialInliner::runOnModule(Module& M) { + if (skipModule(M)) + return false; + std::vector<Function*> worklist; worklist.reserve(M.size()); for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) diff --git a/lib/Transforms/IPO/PruneEH.cpp b/lib/Transforms/IPO/PruneEH.cpp index 940f97b3d33..04383f4f3fa 100644 --- a/lib/Transforms/IPO/PruneEH.cpp +++ b/lib/Transforms/IPO/PruneEH.cpp @@ -63,6 +63,9 @@ Pass *llvm::createPruneEHPass() { return new PruneEH(); } bool PruneEH::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + SmallPtrSet<CallGraphNode *, 8> SCCNodes; CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); bool MadeChange = false; diff --git a/lib/Transforms/IPO/StripDeadPrototypes.cpp b/lib/Transforms/IPO/StripDeadPrototypes.cpp index c94cc7c74a8..2ac854f8e32 100644 --- a/lib/Transforms/IPO/StripDeadPrototypes.cpp +++ b/lib/Transforms/IPO/StripDeadPrototypes.cpp @@ -17,6 +17,7 @@ #include "llvm/Transforms/IPO/StripDeadPrototypes.h" #include "llvm/ADT/Statistic.h" #include "llvm/IR/Module.h" +#include "llvm/IR/OptBisect.h" #include "llvm/Pass.h" #include "llvm/Transforms/IPO.h" @@ -54,6 +55,9 @@ static bool stripDeadPrototypes(Module &M) { } PreservedAnalyses StripDeadPrototypesPass::run(Module &M) { + if (skipPassForModule(name(), M)) + return PreservedAnalyses::all(); + if (stripDeadPrototypes(M)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); @@ -69,6 +73,9 @@ public: *PassRegistry::getPassRegistry()); } bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + return stripDeadPrototypes(M); } }; diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 64595424226..3202837ec30 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -229,6 +229,9 @@ static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) { } bool StripSymbols::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; Changed |= StripDebugInfo(M); if (!OnlyDebugInfo) @@ -237,10 +240,15 @@ bool StripSymbols::runOnModule(Module &M) { } bool StripNonDebugSymbols::runOnModule(Module &M) { + if (skipModule(M)) + return false; + return StripSymbolNames(M, true); } bool StripDebugDeclare::runOnModule(Module &M) { + if (skipModule(M)) + return false; Function *Declare = M.getFunction("llvm.dbg.declare"); std::vector<Constant*> DeadConstants; @@ -286,6 +294,9 @@ bool StripDebugDeclare::runOnModule(Module &M) { /// optimized away by the optimizer. This special pass removes debug info for /// such symbols. bool StripDeadDebugInfo::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; LLVMContext &C = M.getContext(); diff --git a/lib/Transforms/IPO/WholeProgramDevirt.cpp b/lib/Transforms/IPO/WholeProgramDevirt.cpp index 48b05b62c36..e7c161dd029 100644 --- a/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -265,7 +265,12 @@ struct WholeProgramDevirt : public ModulePass { WholeProgramDevirt() : ModulePass(ID) { initializeWholeProgramDevirtPass(*PassRegistry::getPassRegistry()); } - bool runOnModule(Module &M) { return DevirtModule(M).run(); } + bool runOnModule(Module &M) { + if (skipModule(M)) + return false; + + return DevirtModule(M).run(); + } }; } // anonymous namespace diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index 3eebf5b9487..8a9d2821b44 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -56,6 +56,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/OptBisect.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/CommandLine.h" @@ -3088,6 +3089,9 @@ combineInstructionsOverFunction(Function &F, InstCombineWorklist &Worklist, PreservedAnalyses InstCombinePass::run(Function &F, AnalysisManager<Function> &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + auto &AC = AM.getResult<AssumptionAnalysis>(F); auto &DT = AM.getResult<DominatorTreeAnalysis>(F); auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); @@ -3120,7 +3124,7 @@ void InstructionCombiningPass::getAnalysisUsage(AnalysisUsage &AU) const { } bool InstructionCombiningPass::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; // Required analyses. diff --git a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index bf2933e8921..ebfb954d384 100644 --- a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -778,6 +778,9 @@ static void createIRLevelProfileFlagVariable(Module &M) { } bool PGOInstrumentationGen::runOnModule(Module &M) { + if (skipModule(M)) + return false; + createIRLevelProfileFlagVariable(M); for (auto &F : M) { if (F.isDeclaration()) @@ -801,6 +804,9 @@ static void setPGOCountOnFunc(PGOUseFunc &Func, } bool PGOInstrumentationUse::runOnModule(Module &M) { + if (skipModule(M)) + return false; + DEBUG(dbgs() << "Read in profile counters: "); auto &Ctx = M.getContext(); // Read the counter array from file. diff --git a/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp index 1bb0739f32a..b2c62a0e8ee 100644 --- a/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp @@ -132,6 +132,9 @@ bool ObjCARCAPElim::runOnModule(Module &M) { if (!ModuleHasARC(M)) return false; + if (skipModule(M)) + return false; + // Find the llvm.global_ctors variable, as the first step in // identifying the global constructors. In theory, unnecessary autorelease // pools could occur anywhere, but in practice it's pretty rare. Global diff --git a/lib/Transforms/Scalar/ADCE.cpp b/lib/Transforms/Scalar/ADCE.cpp index 579e60f76da..34e15a18ce1 100644 --- a/lib/Transforms/Scalar/ADCE.cpp +++ b/lib/Transforms/Scalar/ADCE.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/OptBisect.h" #include "llvm/Pass.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Transforms/Scalar.h" @@ -146,6 +147,9 @@ static bool aggressiveDCE(Function& F) { } PreservedAnalyses ADCEPass::run(Function &F) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + if (aggressiveDCE(F)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); @@ -159,7 +163,7 @@ struct ADCELegacyPass : public FunctionPass { } bool runOnFunction(Function& F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; return aggressiveDCE(F); } diff --git a/lib/Transforms/Scalar/BDCE.cpp b/lib/Transforms/Scalar/BDCE.cpp index a27eab80046..a357280dcef 100644 --- a/lib/Transforms/Scalar/BDCE.cpp +++ b/lib/Transforms/Scalar/BDCE.cpp @@ -59,7 +59,7 @@ INITIALIZE_PASS_END(BDCE, "bdce", "Bit-Tracking Dead Code Elimination", false, false) bool BDCE::runOnFunction(Function& F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto &DB = getAnalysis<DemandedBitsWrapperPass>().getDemandedBits(); diff --git a/lib/Transforms/Scalar/ConstantHoisting.cpp b/lib/Transforms/Scalar/ConstantHoisting.cpp index d549228757f..74050fa1b5d 100644 --- a/lib/Transforms/Scalar/ConstantHoisting.cpp +++ b/lib/Transforms/Scalar/ConstantHoisting.cpp @@ -187,7 +187,7 @@ FunctionPass *llvm::createConstantHoistingPass() { /// \brief Perform the constant hoisting optimization for the given function. bool ConstantHoisting::runOnFunction(Function &Fn) { - if (skipOptnoneFunction(Fn)) + if (skipFunction(Fn)) return false; DEBUG(dbgs() << "********** Begin Constant Hoisting **********\n"); diff --git a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 8f30d5b51a4..01254711491 100644 --- a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -399,7 +399,7 @@ Constant *CorrelatedValuePropagation::getConstantAt(Value *V, Instruction *At) { } bool CorrelatedValuePropagation::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; LVI = &getAnalysis<LazyValueInfo>(); diff --git a/lib/Transforms/Scalar/DCE.cpp b/lib/Transforms/Scalar/DCE.cpp index b67c3c7742f..a1f2ecf7c88 100644 --- a/lib/Transforms/Scalar/DCE.cpp +++ b/lib/Transforms/Scalar/DCE.cpp @@ -41,7 +41,7 @@ namespace { initializeDeadInstEliminationPass(*PassRegistry::getPassRegistry()); } bool runOnBasicBlock(BasicBlock &BB) override { - if (skipOptnoneFunction(BB)) + if (skipBasicBlock(BB)) return false; auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI() : nullptr; @@ -122,7 +122,7 @@ static bool DCEInstruction(Instruction *I, } bool DCE::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); diff --git a/lib/Transforms/Scalar/DeadStoreElimination.cpp b/lib/Transforms/Scalar/DeadStoreElimination.cpp index 61bbdf00c71..ee0905c7e63 100644 --- a/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -58,7 +58,7 @@ namespace { } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); diff --git a/lib/Transforms/Scalar/EarlyCSE.cpp b/lib/Transforms/Scalar/EarlyCSE.cpp index af0c0ac044f..7be3aab272d 100644 --- a/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/lib/Transforms/Scalar/EarlyCSE.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/OptBisect.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" @@ -819,6 +820,9 @@ bool EarlyCSE::run() { PreservedAnalyses EarlyCSEPass::run(Function &F, AnalysisManager<Function> &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); auto &TTI = AM.getResult<TargetIRAnalysis>(F); auto &DT = AM.getResult<DominatorTreeAnalysis>(F); @@ -853,7 +857,7 @@ public: } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); diff --git a/lib/Transforms/Scalar/Float2Int.cpp b/lib/Transforms/Scalar/Float2Int.cpp index 3c635106605..0a41187a0b8 100644 --- a/lib/Transforms/Scalar/Float2Int.cpp +++ b/lib/Transforms/Scalar/Float2Int.cpp @@ -516,7 +516,7 @@ void Float2Int::cleanup() { } bool Float2Int::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; DEBUG(dbgs() << "F2I: Looking at function " << F.getName() << "\n"); diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 303785f14d2..02e18abd332 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -43,6 +43,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/OptBisect.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -584,6 +585,9 @@ void GVN::ValueTable::verifyRemoved(const Value *V) const { //===----------------------------------------------------------------------===// PreservedAnalyses GVN::run(Function &F, AnalysisManager<Function> &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + // FIXME: The order of evaluation of these 'getResult' calls is very // significant! Re-ordering these variables will cause GVN when run alone to // be less effective! We should fix memdep and basic-aa to not exhibit this @@ -2675,7 +2679,7 @@ public: } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; return Impl.runImpl( diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index 899aa1ea87d..effb8f672ce 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2122,7 +2122,7 @@ void IndVarSimplify::sinkUnusedInvariants(Loop *L) { //===----------------------------------------------------------------------===// bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; // If LoopSimplify form is not available, stay out of trouble. Some notes: diff --git a/lib/Transforms/Scalar/JumpThreading.cpp b/lib/Transforms/Scalar/JumpThreading.cpp index 7495baab1d9..ba406a8e8b3 100644 --- a/lib/Transforms/Scalar/JumpThreading.cpp +++ b/lib/Transforms/Scalar/JumpThreading.cpp @@ -187,7 +187,7 @@ FunctionPass *llvm::createJumpThreadingPass(int Threshold) { return new JumpThre /// runOnFunction - Top level algorithm. /// bool JumpThreading::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; DEBUG(dbgs() << "Jump threading on function '" << F.getName() << "'\n"); diff --git a/lib/Transforms/Scalar/LICM.cpp b/lib/Transforms/Scalar/LICM.cpp index 331cd2d0a60..72f04165e66 100644 --- a/lib/Transforms/Scalar/LICM.cpp +++ b/lib/Transforms/Scalar/LICM.cpp @@ -174,7 +174,7 @@ Pass *llvm::createLICMPass() { return new LICM(); } /// times on one loop. /// bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Changed = false; diff --git a/lib/Transforms/Scalar/LoadCombine.cpp b/lib/Transforms/Scalar/LoadCombine.cpp index 354a3da93e6..a54cd884abe 100644 --- a/lib/Transforms/Scalar/LoadCombine.cpp +++ b/lib/Transforms/Scalar/LoadCombine.cpp @@ -221,7 +221,7 @@ bool LoadCombine::combineLoads(SmallVectorImpl<LoadPOPPair> &Loads) { } bool LoadCombine::runOnBasicBlock(BasicBlock &BB) { - if (skipOptnoneFunction(BB)) + if (skipBasicBlock(BB)) return false; AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp index 856c3ca5c6b..786cd72fbbb 100644 --- a/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/lib/Transforms/Scalar/LoopDeletion.cpp @@ -119,7 +119,7 @@ bool LoopDeletion::isLoopDead(Loop *L, /// NOTE: This entire process relies pretty heavily on LoopSimplify and LCSSA /// in order to make various safety checks work. bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); diff --git a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp index 87439ec9ebe..68bd672c609 100644 --- a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -169,7 +169,7 @@ static void deleteDeadInstruction(Instruction *I, //===----------------------------------------------------------------------===// bool LoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; CurLoop = L; diff --git a/lib/Transforms/Scalar/LoopInstSimplify.cpp b/lib/Transforms/Scalar/LoopInstSimplify.cpp index 4d2f4bc86ad..431ac475ac6 100644 --- a/lib/Transforms/Scalar/LoopInstSimplify.cpp +++ b/lib/Transforms/Scalar/LoopInstSimplify.cpp @@ -65,7 +65,7 @@ Pass *llvm::createLoopInstSimplifyPass() { } bool LoopInstSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; DominatorTreeWrapperPass *DTWP = diff --git a/lib/Transforms/Scalar/LoopLoadElimination.cpp b/lib/Transforms/Scalar/LoopLoadElimination.cpp index 1a51df8a71d..9a7e2c74a8d 100644 --- a/lib/Transforms/Scalar/LoopLoadElimination.cpp +++ b/lib/Transforms/Scalar/LoopLoadElimination.cpp @@ -531,6 +531,9 @@ public: } bool runOnFunction(Function &F) override { + if (skipFunction(F)) + return false; + auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); auto *LAA = &getAnalysis<LoopAccessAnalysis>(); auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); diff --git a/lib/Transforms/Scalar/LoopRerollPass.cpp b/lib/Transforms/Scalar/LoopRerollPass.cpp index 3fb0a104c3f..825cb09a3d2 100644 --- a/lib/Transforms/Scalar/LoopRerollPass.cpp +++ b/lib/Transforms/Scalar/LoopRerollPass.cpp @@ -1536,7 +1536,7 @@ bool LoopReroll::reroll(Instruction *IV, Loop *L, BasicBlock *Header, } bool LoopReroll::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); diff --git a/lib/Transforms/Scalar/LoopRotation.cpp b/lib/Transforms/Scalar/LoopRotation.cpp index 1c567fd6655..ac008288eaa 100644 --- a/lib/Transforms/Scalar/LoopRotation.cpp +++ b/lib/Transforms/Scalar/LoopRotation.cpp @@ -585,7 +585,7 @@ public: } bool runOnLoop(Loop *L, LPPassManager &LPM) override { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Function &F = *L->getHeader()->getParent(); diff --git a/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/lib/Transforms/Scalar/LoopSimplifyCFG.cpp index a15d1e85691..d908dc72391 100644 --- a/lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ b/lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -91,7 +91,7 @@ static bool simplifyLoopCFG(Loop *L, DominatorTree *DT, LoopInfo *LI) { /// runOnLoop - Perform basic CFG simplifications to assist other loop passes. /// For now, this only attempts to merge blocks in the trivial case. bool LoopSimplifyCFG::runOnLoop(Loop *L, LPPassManager &) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); diff --git a/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/lib/Transforms/Scalar/LoopStrengthReduce.cpp index 746adeaf417..b4b6fd1fe78 100644 --- a/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ b/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -5002,7 +5002,7 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const { } bool LoopStrengthReduce::runOnLoop(Loop *L, LPPassManager & /*LPM*/) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; auto &IU = getAnalysis<IVUsers>(); diff --git a/lib/Transforms/Scalar/LoopUnrollPass.cpp b/lib/Transforms/Scalar/LoopUnrollPass.cpp index 01a8ad8a144..685ce9e5e8e 100644 --- a/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ b/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -787,7 +787,7 @@ public: Optional<bool> ProvidedRuntime; bool runOnLoop(Loop *L, LPPassManager &) override { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Function &F = *L->getHeader()->getParent(); diff --git a/lib/Transforms/Scalar/LoopUnswitch.cpp b/lib/Transforms/Scalar/LoopUnswitch.cpp index 955604f0507..310f41ed7df 100644 --- a/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -420,7 +420,7 @@ static Value *FindLIVLoopCondition(Value *Cond, Loop *L, bool &Changed) { } bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache( diff --git a/lib/Transforms/Scalar/LoopVersioningLICM.cpp b/lib/Transforms/Scalar/LoopVersioningLICM.cpp index df0094d97ec..7ccf2271e62 100644 --- a/lib/Transforms/Scalar/LoopVersioningLICM.cpp +++ b/lib/Transforms/Scalar/LoopVersioningLICM.cpp @@ -531,7 +531,7 @@ void LoopVersioningLICM::setNoAliasToLoop(Loop *VerLoop) { } bool LoopVersioningLICM::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Changed = false; // Get Analysis information. diff --git a/lib/Transforms/Scalar/LowerAtomic.cpp b/lib/Transforms/Scalar/LowerAtomic.cpp index 47d374248dc..c7e75470f29 100644 --- a/lib/Transforms/Scalar/LowerAtomic.cpp +++ b/lib/Transforms/Scalar/LowerAtomic.cpp @@ -116,7 +116,7 @@ namespace { initializeLowerAtomicPass(*PassRegistry::getPassRegistry()); } bool runOnBasicBlock(BasicBlock &BB) override { - if (skipOptnoneFunction(BB)) + if (skipBasicBlock(BB)) return false; bool Changed = false; for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { diff --git a/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/lib/Transforms/Scalar/MemCpyOptimizer.cpp index 26359f98ed4..a51204ab2e3 100644 --- a/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -1361,7 +1361,7 @@ bool MemCpyOpt::iterateOnFunction(Function &F) { /// This is the main transformation entry point for a function. bool MemCpyOpt::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; bool MadeChange = false; diff --git a/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp b/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp index cc4ecc736d6..4a08f895b87 100644 --- a/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp +++ b/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp @@ -560,6 +560,9 @@ bool MergedLoadStoreMotion::mergeStores(BasicBlock *T) { /// \brief Run the transformation for each function /// bool MergedLoadStoreMotion::runOnFunction(Function &F) { + if (skipFunction(F)) + return false; + auto *MDWP = getAnalysisIfAvailable<MemoryDependenceWrapperPass>(); MD = MDWP ? &MDWP->getMemDep() : nullptr; AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); diff --git a/lib/Transforms/Scalar/NaryReassociate.cpp b/lib/Transforms/Scalar/NaryReassociate.cpp index 208720ff69d..f69c5df9eac 100644 --- a/lib/Transforms/Scalar/NaryReassociate.cpp +++ b/lib/Transforms/Scalar/NaryReassociate.cpp @@ -208,7 +208,7 @@ FunctionPass *llvm::createNaryReassociatePass() { } bool NaryReassociate::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F); diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp index b22e2cda48d..5e9a0b54861 100644 --- a/lib/Transforms/Scalar/Reassociate.cpp +++ b/lib/Transforms/Scalar/Reassociate.cpp @@ -2257,7 +2257,7 @@ void Reassociate::ReassociateExpression(BinaryOperator *I) { } bool Reassociate::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; // Reassociate needs for each instruction to have its operands already diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 2242a2bcfb1..f1f36b7425e 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -1568,7 +1568,7 @@ FunctionPass *llvm::createSCCPPass() { // and return true if the function was modified. // bool SCCP::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; DEBUG(dbgs() << "SCCP on function '" << F.getName() << "'\n"); @@ -1705,6 +1705,9 @@ static bool AddressIsTaken(const GlobalValue *GV) { } bool IPSCCP::runOnModule(Module &M) { + if (skipModule(M)) + return false; + const DataLayout &DL = M.getDataLayout(); const TargetLibraryInfo *TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); diff --git a/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp index 3c42b7957c3..67588799d4e 100644 --- a/lib/Transforms/Scalar/SROA.cpp +++ b/lib/Transforms/Scalar/SROA.cpp @@ -43,6 +43,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/OptBisect.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -4229,6 +4230,9 @@ PreservedAnalyses SROA::runImpl(Function &F, DominatorTree &RunDT, } PreservedAnalyses SROA::run(Function &F, AnalysisManager<Function> &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + return runImpl(F, AM.getResult<DominatorTreeAnalysis>(F), AM.getResult<AssumptionAnalysis>(F)); } @@ -4246,7 +4250,7 @@ public: initializeSROALegacyPassPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto PA = Impl.runImpl( diff --git a/lib/Transforms/Scalar/ScalarReplAggregates.cpp b/lib/Transforms/Scalar/ScalarReplAggregates.cpp index 6633388ae14..5e782692a78 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregates.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -1026,7 +1026,7 @@ ConvertScalar_InsertValue(Value *SV, Value *Old, bool SROA::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; bool Changed = performPromotion(F); diff --git a/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp index f94aa9e3e7f..2bc0087f063 100644 --- a/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp +++ b/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp @@ -1064,7 +1064,7 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) { } bool SeparateConstOffsetFromGEP::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; if (DisableSeparateConstOffsetFromGEP) diff --git a/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/lib/Transforms/Scalar/SimplifyCFGPass.cpp index 30fbe047190..7835eb6ceef 100644 --- a/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -36,6 +36,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" +#include "llvm/IR/OptBisect.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils/Local.h" @@ -187,6 +188,9 @@ SimplifyCFGPass::SimplifyCFGPass(int BonusInstThreshold) PreservedAnalyses SimplifyCFGPass::run(Function &F, AnalysisManager<Function> &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + auto &TTI = AM.getResult<TargetIRAnalysis>(F); auto &AC = AM.getResult<AssumptionAnalysis>(F); @@ -212,7 +216,7 @@ struct CFGSimplifyPass : public FunctionPass { if (PredicateFtor && !PredicateFtor(F)) return false; - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; AssumptionCache *AC = diff --git a/lib/Transforms/Scalar/SpeculativeExecution.cpp b/lib/Transforms/Scalar/SpeculativeExecution.cpp index 6b82943abf3..2d49d763fc4 100644 --- a/lib/Transforms/Scalar/SpeculativeExecution.cpp +++ b/lib/Transforms/Scalar/SpeculativeExecution.cpp @@ -141,7 +141,7 @@ void SpeculativeExecution::getAnalysisUsage(AnalysisUsage &AU) const { } bool SpeculativeExecution::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); diff --git a/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp index 8ee0bbb21ce..03de393ca73 100644 --- a/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp +++ b/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp @@ -682,7 +682,7 @@ void StraightLineStrengthReduce::rewriteCandidateWithBasis( } bool StraightLineStrengthReduce::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp index c8099446013..132bf82a117 100644 --- a/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -157,7 +157,7 @@ static bool CanTRE(Function &F) { } bool TailCallElim::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true") diff --git a/lib/Transforms/Utils/Mem2Reg.cpp b/lib/Transforms/Utils/Mem2Reg.cpp index aa1e35ddba0..8b70cb80539 100644 --- a/lib/Transforms/Utils/Mem2Reg.cpp +++ b/lib/Transforms/Utils/Mem2Reg.cpp @@ -59,13 +59,13 @@ INITIALIZE_PASS_END(PromotePass, "mem2reg", "Promote Memory to Register", false, false) bool PromotePass::runOnFunction(Function &F) { + if (skipFunction(F)) + return false; + std::vector<AllocaInst*> Allocas; BasicBlock &BB = F.getEntryBlock(); // Get the entry node for the function - if (F.hasFnAttribute(Attribute::OptimizeNone)) - return false; - bool Changed = false; DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); diff --git a/lib/Transforms/Vectorize/BBVectorize.cpp b/lib/Transforms/Vectorize/BBVectorize.cpp index b43951d3f40..72ac7a5ba2b 100644 --- a/lib/Transforms/Vectorize/BBVectorize.cpp +++ b/lib/Transforms/Vectorize/BBVectorize.cpp @@ -397,7 +397,7 @@ namespace { Instruction *I, Instruction *J); bool vectorizeBB(BasicBlock &BB) { - if (skipOptnoneFunction(BB)) + if (skipBasicBlock(BB)) return false; if (!DT->isReachableFromEntry(&BB)) { DEBUG(dbgs() << "BBV: skipping unreachable " << BB.getName() << diff --git a/lib/Transforms/Vectorize/LoopVectorize.cpp b/lib/Transforms/Vectorize/LoopVectorize.cpp index 90170e797eb..6c571984b49 100644 --- a/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -1707,6 +1707,9 @@ struct LoopVectorize : public FunctionPass { BlockFrequency ColdEntryFreq; bool runOnFunction(Function &F) override { + if (skipFunction(F)) + return false; + SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE(); LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); diff --git a/lib/Transforms/Vectorize/SLPVectorizer.cpp b/lib/Transforms/Vectorize/SLPVectorizer.cpp index 500919febc9..f1bfbc2ba84 100644 --- a/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -3396,7 +3396,7 @@ struct SLPVectorizer : public FunctionPass { } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE(); diff --git a/test/Other/opt-bisect-helper.py b/test/Other/opt-bisect-helper.py new file mode 100755 index 00000000000..d75950f11d8 --- /dev/null +++ b/test/Other/opt-bisect-helper.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +import os +import sys +import argparse +import subprocess + +parser = argparse.ArgumentParser() + +parser.add_argument('--start', type=int, default=0) +parser.add_argument('--end', type=int, default=(1 << 32)) +parser.add_argument('--optcmd', default=("opt")) +parser.add_argument('--filecheckcmd', default=("FileCheck")) +parser.add_argument('--prefix', default=("CHECK-BISECT")) +parser.add_argument('--test', default=("")) + +args = parser.parse_args() + +start = args.start +end = args.end + +opt_command = [args.optcmd, "-O2", "-opt-bisect-limit=%(count)s", "-S", args.test] +check_command = [args.filecheckcmd, args.test, "--check-prefix=%s" % args.prefix] +last = None +while start != end and start != end-1: + count = int(round(start + (end - start)/2)) + cmd = [x % {'count':count} for x in opt_command] + print("opt: " + str(cmd)) + opt_result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + filecheck_result = subprocess.Popen(check_command, stdin=opt_result.stdout) + opt_result.stdout.close() + opt_result.stderr.close() + filecheck_result.wait() + if filecheck_result.returncode == 0: + start = count + else: + end = count + +print("Last good count: %d" % start) diff --git a/test/Other/opt-bisect-legacy-pass-manager.ll b/test/Other/opt-bisect-legacy-pass-manager.ll new file mode 100644 index 00000000000..8c39187fcf0 --- /dev/null +++ b/test/Other/opt-bisect-legacy-pass-manager.ll @@ -0,0 +1,148 @@ +; This file verifies the behavior of the OptBisect class, which is used to +; diagnose optimization related failures. The tests check various +; invocations that result in different sets of optimization passes that +; are run in different ways. +; +; This set of tests exercises the legacy pass manager interface to the OptBisect +; class. Because the exact set of optimizations that will be run may +; change over time, these tests are written in a more general manner than the +; corresponding tests for the new pass manager. +; +; Don't use NEXT checks or hard-code pass numbering so that this won't fail if +; new passes are inserted. + + +; Verify that the file can be compiled to an object file at -O3 with all +; skippable passes skipped. + +; RUN: opt -O3 -opt-bisect-limit=0 < %s | llc -O3 -opt-bisect-limit=0 + + +; Verify that no skippable passes are run with -opt-bisect-limit=0. + +; RUN: opt -disable-output -disable-verify -O3 -opt-bisect-limit=0 %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-SKIP-ALL +; CHECK-SKIP-ALL: BISECT: NOT running pass ({{[0-9]+}}) +; CHECK-SKIP-ALL-NOT: BISECT: running pass ({{[0-9]+}}) + + +; Verify that we can use the opt-bisect-helper.py script (derived from +; utils/bisect) to locate the optimization that inlines the call to +; f2() in f3(). + +; RUN: %python %S/opt-bisect-helper.py --start=0 --end=256 --optcmd=opt \ +; RUN: --filecheckcmd=FileCheck --test=%s \ +; RUN: --prefix=CHECK-BISECT-INLINE-HELPER \ +; RUN: | FileCheck %s --check-prefix=CHECK-BISECT-INLINE-RESULT +; The helper script uses this to find the optimization that inlines the call. +; CHECK-BISECT-INLINE-HELPER: call i32 @f2() +; These checks verifies that the optimization was found. +; CHECK-BISECT-INLINE-RESULT-NOT: Last good count: 0 +; CHECK-BISECT-INLINE-RESULT: Last good count: {{[0-9]+}} + + +; Test a module pass. + +; RUN: opt -disable-output -disable-verify -deadargelim -opt-bisect-limit=-1 %s \ +; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-DEADARG +; CHECK-DEADARG: BISECT: running pass ({{[0-9]+}}) Dead Argument Elimination on module + +; RUN: opt -disable-output -disable-verify -deadargelim -opt-bisect-limit=0 %s \ +; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-DEADARG +; CHECK-NOT-DEADARG: BISECT: NOT running pass ({{[0-9]+}}) Dead Argument Elimination on module + + +; Test an SCC pass. + +; RUN: opt -disable-output -disable-verify -inline -opt-bisect-limit=-1 %s \ +; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-INLINE +; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) +; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (g) +; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f1) +; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f2) +; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f3) +; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) + +; RUN: opt -disable-output -disable-verify -inline -opt-bisect-limit=0 %s \ +; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-INLINE +; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) +; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (g) +; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f1) +; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f2) +; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f3) +; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) + + +; Test a function pass. + +; RUN: opt -disable-output -disable-verify -early-cse -opt-bisect-limit=-1 \ +; RUN: %s 2>&1 | FileCheck %s --check-prefix=CHECK-EARLY-CSE +; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f1) +; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f2) +; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f3) + +; RUN: opt -disable-output -disable-verify -early-cse -opt-bisect-limit=0 %s \ +; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-EARLY-CSE +; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f1) +; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f2) +; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f3) + + +; Test a loop pass. + +; RUN: opt -disable-output -disable-verify -loop-reduce -opt-bisect-limit=-1 \ +; RUN: %s 2>&1 | FileCheck %s --check-prefix=CHECK-LOOP-REDUCE +; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop + +; RUN: opt -disable-output -disable-verify -loop-reduce -opt-bisect-limit=0 \ +; RUN: %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-LOOP-REDUCE +; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop +; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop + + +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 +} diff --git a/test/Other/opt-bisect-new-pass-manager.ll b/test/Other/opt-bisect-new-pass-manager.ll new file mode 100644 index 00000000000..3927422d6ed --- /dev/null +++ b/test/Other/opt-bisect-new-pass-manager.ll @@ -0,0 +1,109 @@ +; This file verifies the behavior of the OptBisect class, which is used to +; diagnose optimization related failures. The tests check various +; invocations that result in different sets of optimization passes that +; are run in different ways. +; +; Because the exact set of optimizations that will be run is expected to +; change over time, the checks for disabling passes are written in a +; conservative way that avoids assumptions about which specific passes +; will be disabled. + +; 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 + +; 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 + +; 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 function (f1) +; CHECK-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on function (f2) +; CHECK-FUNCTION-PASS: BISECT: running pass (3) EarlyCSEPass on function (f3) + +; 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 function (f1) +; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on function (f2) +; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (3) EarlyCSEPass on function (f3) + +; 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 SCC (f2) +; CHECK-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on SCC (f3) +; CHECK-CGSCC-PASS: BISECT: running pass (3) PostOrderFunctionAttrsPass on SCC (f1) + +; RUN: opt -disable-output -disable-verify \ +; RUN: -passes=function-attrs -opt-bisect-limit=2 %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-CGSCC-PASS +; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on SCC (f2) +; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on SCC (f3) +; CHECK-LIMIT-CGSCC-PASS: BISECT: NOT running pass (3) PostOrderFunctionAttrsPass on SCC (f1) + +; 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 SCC (f2) +; CHECK-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on function (f2) +; CHECK-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on SCC (f3) +; CHECK-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on function (f3) +; CHECK-MULTI-PASS: BISECT: running pass (6) PostOrderFunctionAttrsPass on SCC (f1) +; CHECK-MULTI-PASS: BISECT: running pass (7) EarlyCSEPass on function (f1) + +; RUN: opt -disable-output -disable-verify -opt-bisect-limit=5 \ +; 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 SCC (f2) +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on function (f2) +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on SCC (f3) +; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on function (f3) +; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (6) PostOrderFunctionAttrsPass on SCC (f1) +; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (7) EarlyCSEPass on function (f1) + +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 +} |