From: Andrew Kaylor Date: Thu, 21 Apr 2016 17:58:54 +0000 (+0000) Subject: Initial implementation of optimization bisect support. X-Git-Tag: android-x86-7.1-r4~34841 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=c852398cbc35e0ddff7a104420ded35316e2106a;p=android-x86%2Fexternal-llvm.git Initial implementation of optimization bisect support. This patch implements a optimization bisect feature, which will allow optimizations to be selectively disabled at compile time in order to track down test failures that are caused by incorrect optimizations. The bisection is enabled using a new command line option (-opt-bisect-limit). Individual passes that may be skipped call the OptBisect object (via an LLVMContext) to see if they should be skipped based on the bisect limit. A finer level of control (disabling individual transformations) can be managed through an addition OptBisect method, but this is not yet used. The skip checking in this implementation is based on (and replaces) the skipOptnoneFunction check. Where that check was being called, a new call has been inserted in its place which checks the bisect limit and the optnone attribute. A new function call has been added for module and SCC passes that behaves in a similar way. Differential Revision: http://reviews.llvm.org/D19172 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267022 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 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::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 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(); } + /// \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 + 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 + 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 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(); 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(); 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 &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(); 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 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 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 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 += "<>"; + } + 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 +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 +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 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(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().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 &AM) { + if (skipPassForModule(name(), M)) + return PreservedAnalyses::all(); + auto &TLI = AM.getResult(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().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().getCallGraph(); ACT = &getAnalysis(); auto &TLI = getAnalysis().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(); 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 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 &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 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 SCCNodes; CallGraph &CG = getAnalysis().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 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 &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + auto &AC = AM.getResult(F); auto &DT = AM.getResult(F); auto &TLI = AM.getResult(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().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(); 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(); 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(); 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().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 &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + auto &TLI = AM.getResult(F); auto &TTI = AM.getResult(F); auto &DT = AM.getResult(F); @@ -853,7 +857,7 @@ public: } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto &TLI = getAnalysis().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 &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 &Loads) { } bool LoadCombine::runOnBasicBlock(BasicBlock &BB) { - if (skipOptnoneFunction(BB)) + if (skipBasicBlock(BB)) return false; AA = &getAnalysis().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().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().getLoopInfo(); auto *LAA = &getAnalysis(); auto *DT = &getAnalysis().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().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().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(); 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 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().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(); MD = MDWP ? &MDWP->getMemDep() : nullptr; AA = &getAnalysis().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().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().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 &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + return runImpl(F, AM.getResult(F), AM.getResult(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 &AM) { + if (skipPassForFunction(name(), F)) + return PreservedAnalyses::all(); + auto &TTI = AM.getResult(F); auto &AC = AM.getResult(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().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().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 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().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().getSE(); LI = &getAnalysis().getLoopInfo(); TTI = &getAnalysis().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().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 (<>) +; 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 (<>) + +; 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 (<>) +; 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 (<>) + + +; 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 +}