Index: llvm/trunk/include/llvm/Analysis/CallGraphSCCPass.h =================================================================== --- llvm/trunk/include/llvm/Analysis/CallGraphSCCPass.h +++ llvm/trunk/include/llvm/Analysis/CallGraphSCCPass.h @@ -77,15 +77,21 @@ /// 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 @@ 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 Index: llvm/trunk/include/llvm/Analysis/LazyCallGraph.h =================================================================== --- llvm/trunk/include/llvm/Analysis/LazyCallGraph.h +++ llvm/trunk/include/llvm/Analysis/LazyCallGraph.h @@ -923,6 +923,15 @@ 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 Index: llvm/trunk/include/llvm/Analysis/LoopPass.h =================================================================== --- llvm/trunk/include/llvm/Analysis/LoopPass.h +++ llvm/trunk/include/llvm/Analysis/LoopPass.h @@ -88,9 +88,10 @@ 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 { Index: llvm/trunk/include/llvm/IR/LLVMContext.h =================================================================== --- llvm/trunk/include/llvm/IR/LLVMContext.h +++ llvm/trunk/include/llvm/IR/LLVMContext.h @@ -32,6 +32,7 @@ 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 @@ 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; Index: llvm/trunk/include/llvm/IR/OptBisect.h =================================================================== --- llvm/trunk/include/llvm/IR/OptBisect.h +++ llvm/trunk/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 Index: llvm/trunk/include/llvm/Pass.h =================================================================== --- llvm/trunk/include/llvm/Pass.h +++ llvm/trunk/include/llvm/Pass.h @@ -251,6 +251,11 @@ 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 @@ 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 @@ 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 Index: llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp =================================================================== --- llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp +++ llvm/trunk/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 @@ // 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 @@ return new PrintCallGraphPass(Banner, O); } +bool CallGraphSCCPass::skipSCC(CallGraphSCC &SCC) const { + return !SCC.getCallGraph().getModule() + .getContext() + .getOptBisect() + .shouldRunPass(this, SCC); +} Index: llvm/trunk/lib/Analysis/LoopPass.cpp =================================================================== --- llvm/trunk/lib/Analysis/LoopPass.cpp +++ llvm/trunk/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 @@ 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"); Index: llvm/trunk/lib/CodeGen/BranchFolding.cpp =================================================================== --- llvm/trunk/lib/CodeGen/BranchFolding.cpp +++ llvm/trunk/lib/CodeGen/BranchFolding.cpp @@ -90,7 +90,7 @@ "Control Flow Optimizer", false, false) bool BranchFolderPass::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; TargetPassConfig *PassConfig = &getAnalysis(); Index: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp @@ -211,7 +211,7 @@ } bool CodeGenPrepare::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; DL = &F.getParent()->getDataLayout(); Index: llvm/trunk/lib/CodeGen/DeadMachineInstructionElim.cpp =================================================================== --- llvm/trunk/lib/CodeGen/DeadMachineInstructionElim.cpp +++ llvm/trunk/lib/CodeGen/DeadMachineInstructionElim.cpp @@ -90,7 +90,7 @@ } bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; bool AnyChanges = false; Index: llvm/trunk/lib/CodeGen/LowerEmuTLS.cpp =================================================================== --- llvm/trunk/lib/CodeGen/LowerEmuTLS.cpp +++ llvm/trunk/lib/CodeGen/LowerEmuTLS.cpp @@ -63,6 +63,9 @@ } bool LowerEmuTLS::runOnModule(Module &M) { + if (skipModule(M)) + return false; + if (!TM || !TM->Options.EmulatedTLS) return false; Index: llvm/trunk/lib/CodeGen/MachineBlockPlacement.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineBlockPlacement.cpp +++ llvm/trunk/lib/CodeGen/MachineBlockPlacement.cpp @@ -1430,7 +1430,7 @@ if (std::next(F.begin()) == F.end()) return false; - if (skipOptnoneFunction(*F.getFunction())) + if (skipFunction(*F.getFunction())) return false; MBPI = &getAnalysis(); Index: llvm/trunk/lib/CodeGen/MachineCSE.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineCSE.cpp +++ llvm/trunk/lib/CodeGen/MachineCSE.cpp @@ -704,7 +704,7 @@ } bool MachineCSE::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; TII = MF.getSubtarget().getInstrInfo(); Index: llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp +++ llvm/trunk/lib/CodeGen/MachineCopyPropagation.cpp @@ -349,7 +349,7 @@ } bool MachineCopyPropagation::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; Changed = false; Index: llvm/trunk/lib/CodeGen/MachineLICM.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineLICM.cpp +++ llvm/trunk/lib/CodeGen/MachineLICM.cpp @@ -260,7 +260,7 @@ } bool MachineLICM::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; Changed = FirstInLoop = false; Index: llvm/trunk/lib/CodeGen/MachineScheduler.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineScheduler.cpp +++ llvm/trunk/lib/CodeGen/MachineScheduler.cpp @@ -319,7 +319,7 @@ /// 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 PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) { - if (skipOptnoneFunction(*mf.getFunction())) + if (skipFunction(*mf.getFunction())) return false; if (EnablePostRAMachineSched.getNumOccurrences()) { Index: llvm/trunk/lib/CodeGen/MachineSink.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineSink.cpp +++ llvm/trunk/lib/CodeGen/MachineSink.cpp @@ -257,7 +257,7 @@ } bool MachineSinking::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; DEBUG(dbgs() << "******** Machine Sinking ********\n"); Index: llvm/trunk/lib/CodeGen/OptimizePHIs.cpp =================================================================== --- llvm/trunk/lib/CodeGen/OptimizePHIs.cpp +++ llvm/trunk/lib/CodeGen/OptimizePHIs.cpp @@ -63,7 +63,7 @@ "Optimize machine instruction PHIs", false, false) bool OptimizePHIs::runOnMachineFunction(MachineFunction &Fn) { - if (skipOptnoneFunction(*Fn.getFunction())) + if (skipFunction(*Fn.getFunction())) return false; MRI = &Fn.getRegInfo(); Index: llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp =================================================================== --- llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp +++ llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp @@ -1471,7 +1471,7 @@ } bool PeepholeOptimizer::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; DEBUG(dbgs() << "********** PEEPHOLE OPTIMIZER **********\n"); Index: llvm/trunk/lib/CodeGen/PostRASchedulerList.cpp =================================================================== --- llvm/trunk/lib/CodeGen/PostRASchedulerList.cpp +++ llvm/trunk/lib/CodeGen/PostRASchedulerList.cpp @@ -273,7 +273,7 @@ } bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { - if (skipOptnoneFunction(*Fn.getFunction())) + if (skipFunction(*Fn.getFunction())) return false; TII = Fn.getSubtarget().getInstrInfo(); Index: llvm/trunk/lib/CodeGen/StackColoring.cpp =================================================================== --- llvm/trunk/lib/CodeGen/StackColoring.cpp +++ llvm/trunk/lib/CodeGen/StackColoring.cpp @@ -657,7 +657,7 @@ } bool StackColoring::runOnMachineFunction(MachineFunction &Func) { - if (skipOptnoneFunction(*Func.getFunction())) + if (skipFunction(*Func.getFunction())) return false; DEBUG(dbgs() << "********** Stack Coloring **********\n" Index: llvm/trunk/lib/CodeGen/TailDuplication.cpp =================================================================== --- llvm/trunk/lib/CodeGen/TailDuplication.cpp +++ llvm/trunk/lib/CodeGen/TailDuplication.cpp @@ -44,7 +44,7 @@ false) bool TailDuplicatePass::runOnMachineFunction(MachineFunction &MF) { - if (skipOptnoneFunction(*MF.getFunction())) + if (skipFunction(*MF.getFunction())) return false; auto MMI = getAnalysisIfAvailable(); Index: llvm/trunk/lib/IR/CMakeLists.txt =================================================================== --- llvm/trunk/lib/IR/CMakeLists.txt +++ llvm/trunk/lib/IR/CMakeLists.txt @@ -39,6 +39,7 @@ Module.cpp ModuleSummaryIndex.cpp Operator.cpp + OptBisect.cpp Pass.cpp PassManager.cpp PassRegistry.cpp Index: llvm/trunk/lib/IR/LLVMContext.cpp =================================================================== --- llvm/trunk/lib/IR/LLVMContext.cpp +++ llvm/trunk/lib/IR/LLVMContext.cpp @@ -325,3 +325,7 @@ void LLVMContext::setDiscardValueNames(bool Discard) { pImpl->DiscardValueNames = Discard; } + +OptBisect &LLVMContext::getOptBisect() { + return pImpl->getOptBisect(); +} Index: llvm/trunk/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/trunk/lib/IR/LLVMContextImpl.h +++ llvm/trunk/lib/IR/LLVMContextImpl.h @@ -1133,6 +1133,10 @@ /// Destroy the ConstantArrays if they are not used. void dropTriviallyDeadConstantArrays(); + + /// \brief Access the object which manages optimization bisection for failure + /// analysis. + OptBisect &getOptBisect(); }; } Index: llvm/trunk/lib/IR/LLVMContextImpl.cpp =================================================================== --- llvm/trunk/lib/IR/LLVMContextImpl.cpp +++ llvm/trunk/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 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; +} Index: llvm/trunk/lib/IR/OptBisect.cpp =================================================================== --- llvm/trunk/lib/IR/OptBisect.cpp +++ llvm/trunk/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); +} + Index: llvm/trunk/lib/IR/Pass.cpp =================================================================== --- llvm/trunk/lib/IR/Pass.cpp +++ llvm/trunk/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 @@ 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 @@ 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 @@ 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() Index: llvm/trunk/lib/Transforms/IPO/ArgumentPromotion.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/ArgumentPromotion.cpp +++ llvm/trunk/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -114,6 +114,9 @@ } bool ArgPromotion::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + bool Changed = false, LocalChange; do { // Iterate until we stop promoting from this SCC. Index: llvm/trunk/lib/Transforms/IPO/ConstantMerge.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/ConstantMerge.cpp +++ llvm/trunk/lib/Transforms/IPO/ConstantMerge.cpp @@ -96,6 +96,8 @@ } bool ConstantMerge::runOnModule(Module &M) { + if (skipModule(M)) + return false; // Find all the globals that are marked "used". These cannot be merged. SmallPtrSet UsedGlobals; Index: llvm/trunk/lib/Transforms/IPO/CrossDSOCFI.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/CrossDSOCFI.cpp +++ llvm/trunk/lib/Transforms/IPO/CrossDSOCFI.cpp @@ -158,6 +158,9 @@ } bool CrossDSOCFI::runOnModule(Module &M) { + if (skipModule(M)) + return false; + if (M.getModuleFlag("Cross-DSO CFI") == nullptr) return false; buildCFICheck(); Index: llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -1092,6 +1092,9 @@ } 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 "..." Index: llvm/trunk/lib/Transforms/IPO/ElimAvailExtern.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/ElimAvailExtern.cpp +++ llvm/trunk/lib/Transforms/IPO/ElimAvailExtern.cpp @@ -50,6 +50,9 @@ } bool EliminateAvailableExternally::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; // Drop initializers of available externally global variables. Index: llvm/trunk/lib/Transforms/IPO/ExtractGV.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/ExtractGV.cpp +++ llvm/trunk/lib/Transforms/IPO/ExtractGV.cpp @@ -68,6 +68,9 @@ : 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(""); Index: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp @@ -987,6 +987,9 @@ 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 @@ 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 @@ } 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 Index: llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp +++ llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp @@ -499,6 +499,9 @@ : 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"); Index: llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp +++ llvm/trunk/lib/Transforms/IPO/GlobalDCE.cpp @@ -75,6 +75,9 @@ 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. Index: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp +++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp @@ -2528,6 +2528,9 @@ } bool GlobalOpt::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; auto &DL = M.getDataLayout(); Index: llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp +++ llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp @@ -54,6 +54,9 @@ ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); } bool IPCP::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; bool LocalChange = true; Index: llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp +++ llvm/trunk/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 @@ 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 @@ } bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + auto &TLI = getAnalysis().getTLI(); return inferAllPrototypeAttributes(M, TLI); } Index: llvm/trunk/lib/Transforms/IPO/Inliner.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/Inliner.cpp +++ llvm/trunk/lib/Transforms/IPO/Inliner.cpp @@ -356,6 +356,9 @@ } bool Inliner::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + CallGraph &CG = getAnalysis().getCallGraph(); ACT = &getAnalysis(); auto &TLI = getAnalysis().getTLI(); Index: llvm/trunk/lib/Transforms/IPO/Internalize.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/Internalize.cpp +++ llvm/trunk/lib/Transforms/IPO/Internalize.cpp @@ -105,6 +105,9 @@ } bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + CallGraphWrapperPass *CGPass = getAnalysisIfAvailable(); CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr; Index: llvm/trunk/lib/Transforms/IPO/LoopExtractor.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/LoopExtractor.cpp +++ llvm/trunk/lib/Transforms/IPO/LoopExtractor.cpp @@ -81,7 +81,7 @@ 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 @@ } 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]; Index: llvm/trunk/lib/Transforms/IPO/LowerBitSets.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/LowerBitSets.cpp +++ llvm/trunk/lib/Transforms/IPO/LowerBitSets.cpp @@ -1051,6 +1051,9 @@ } bool LowerBitSets::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = buildBitSets(); Changed |= eraseBitSetMetadata(); return Changed; Index: llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp +++ llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp @@ -1525,6 +1525,9 @@ } 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 Index: llvm/trunk/lib/Transforms/IPO/PartialInlining.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/PartialInlining.cpp +++ llvm/trunk/lib/Transforms/IPO/PartialInlining.cpp @@ -149,6 +149,9 @@ } 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) Index: llvm/trunk/lib/Transforms/IPO/PruneEH.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/PruneEH.cpp +++ llvm/trunk/lib/Transforms/IPO/PruneEH.cpp @@ -63,6 +63,9 @@ bool PruneEH::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + SmallPtrSet SCCNodes; CallGraph &CG = getAnalysis().getCallGraph(); bool MadeChange = false; Index: llvm/trunk/lib/Transforms/IPO/StripDeadPrototypes.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/StripDeadPrototypes.cpp +++ llvm/trunk/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 @@ } 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 @@ *PassRegistry::getPassRegistry()); } bool runOnModule(Module &M) override { + if (skipModule(M)) + return false; + return stripDeadPrototypes(M); } }; Index: llvm/trunk/lib/Transforms/IPO/StripSymbols.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/StripSymbols.cpp +++ llvm/trunk/lib/Transforms/IPO/StripSymbols.cpp @@ -229,6 +229,9 @@ } bool StripSymbols::runOnModule(Module &M) { + if (skipModule(M)) + return false; + bool Changed = false; Changed |= StripDebugInfo(M); if (!OnlyDebugInfo) @@ -237,10 +240,15 @@ } 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 @@ /// 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(); Index: llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -265,7 +265,12 @@ 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 Index: llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/trunk/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 @@ 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 @@ } bool InstructionCombiningPass::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; // Required analyses. Index: llvm/trunk/lib/Transforms/Instrumentation/PGOInstrumentation.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -778,6 +778,9 @@ } bool PGOInstrumentationGen::runOnModule(Module &M) { + if (skipModule(M)) + return false; + createIRLevelProfileFlagVariable(M); for (auto &F : M) { if (F.isDeclaration()) @@ -801,6 +804,9 @@ } 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. Index: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp =================================================================== --- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp +++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp @@ -132,6 +132,9 @@ 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 Index: llvm/trunk/lib/Transforms/Scalar/ADCE.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/ADCE.cpp +++ llvm/trunk/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 @@ } 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 @@ } bool runOnFunction(Function& F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; return aggressiveDCE(F); } Index: llvm/trunk/lib/Transforms/Scalar/BDCE.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/BDCE.cpp +++ llvm/trunk/lib/Transforms/Scalar/BDCE.cpp @@ -59,7 +59,7 @@ false, false) bool BDCE::runOnFunction(Function& F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto &DB = getAnalysis().getDemandedBits(); Index: llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp +++ llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp @@ -187,7 +187,7 @@ /// \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"); Index: llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -399,7 +399,7 @@ } bool CorrelatedValuePropagation::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; LVI = &getAnalysis(); Index: llvm/trunk/lib/Transforms/Scalar/DCE.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/DCE.cpp +++ llvm/trunk/lib/Transforms/Scalar/DCE.cpp @@ -41,7 +41,7 @@ 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 @@ } bool DCE::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto *TLIP = getAnalysisIfAvailable(); Index: llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -58,7 +58,7 @@ } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; AA = &getAnalysis().getAAResults(); Index: llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp +++ llvm/trunk/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 @@ 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 @@ } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto &TLI = getAnalysis().getTLI(); Index: llvm/trunk/lib/Transforms/Scalar/Float2Int.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/Float2Int.cpp +++ llvm/trunk/lib/Transforms/Scalar/Float2Int.cpp @@ -516,7 +516,7 @@ } bool Float2Int::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; DEBUG(dbgs() << "F2I: Looking at function " << F.getName() << "\n"); Index: llvm/trunk/lib/Transforms/Scalar/GVN.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/GVN.cpp +++ llvm/trunk/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 @@ //===----------------------------------------------------------------------===// 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 @@ } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; return Impl.runImpl( Index: llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp +++ llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2122,7 +2122,7 @@ //===----------------------------------------------------------------------===// 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: Index: llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp +++ llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp @@ -187,7 +187,7 @@ /// 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"); Index: llvm/trunk/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LICM.cpp +++ llvm/trunk/lib/Transforms/Scalar/LICM.cpp @@ -174,7 +174,7 @@ /// times on one loop. /// bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Changed = false; Index: llvm/trunk/lib/Transforms/Scalar/LoadCombine.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoadCombine.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoadCombine.cpp @@ -221,7 +221,7 @@ } bool LoadCombine::runOnBasicBlock(BasicBlock &BB) { - if (skipOptnoneFunction(BB)) + if (skipBasicBlock(BB)) return false; AA = &getAnalysis().getAAResults(); Index: llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp @@ -119,7 +119,7 @@ /// 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(); Index: llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -169,7 +169,7 @@ //===----------------------------------------------------------------------===// bool LoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; CurLoop = L; Index: llvm/trunk/lib/Transforms/Scalar/LoopInstSimplify.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopInstSimplify.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopInstSimplify.cpp @@ -65,7 +65,7 @@ } bool LoopInstSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; DominatorTreeWrapperPass *DTWP = Index: llvm/trunk/lib/Transforms/Scalar/LoopLoadElimination.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopLoadElimination.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopLoadElimination.cpp @@ -531,6 +531,9 @@ } bool runOnFunction(Function &F) override { + if (skipFunction(F)) + return false; + auto *LI = &getAnalysis().getLoopInfo(); auto *LAA = &getAnalysis(); auto *DT = &getAnalysis().getDomTree(); Index: llvm/trunk/lib/Transforms/Scalar/LoopRerollPass.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopRerollPass.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopRerollPass.cpp @@ -1536,7 +1536,7 @@ } bool LoopReroll::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; AA = &getAnalysis().getAAResults(); Index: llvm/trunk/lib/Transforms/Scalar/LoopRotation.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopRotation.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopRotation.cpp @@ -585,7 +585,7 @@ } bool runOnLoop(Loop *L, LPPassManager &LPM) override { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Function &F = *L->getHeader()->getParent(); Index: llvm/trunk/lib/Transforms/Scalar/LoopSimplifyCFG.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -91,7 +91,7 @@ /// 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(); Index: llvm/trunk/lib/Transforms/Scalar/LoopStrengthReduce.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -5002,7 +5002,7 @@ } bool LoopStrengthReduce::runOnLoop(Loop *L, LPPassManager & /*LPM*/) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; auto &IU = getAnalysis(); Index: llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -787,7 +787,7 @@ Optional ProvidedRuntime; bool runOnLoop(Loop *L, LPPassManager &) override { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Function &F = *L->getHeader()->getParent(); Index: llvm/trunk/lib/Transforms/Scalar/LoopUnswitch.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopUnswitch.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -420,7 +420,7 @@ } bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; AC = &getAnalysis().getAssumptionCache( Index: llvm/trunk/lib/Transforms/Scalar/LoopVersioningLICM.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopVersioningLICM.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopVersioningLICM.cpp @@ -531,7 +531,7 @@ } bool LoopVersioningLICM::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipOptnoneFunction(L)) + if (skipLoop(L)) return false; Changed = false; // Get Analysis information. Index: llvm/trunk/lib/Transforms/Scalar/LowerAtomic.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LowerAtomic.cpp +++ llvm/trunk/lib/Transforms/Scalar/LowerAtomic.cpp @@ -116,7 +116,7 @@ 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; ) { Index: llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -1361,7 +1361,7 @@ /// 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; Index: llvm/trunk/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp +++ llvm/trunk/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp @@ -560,6 +560,9 @@ /// \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(); Index: llvm/trunk/lib/Transforms/Scalar/NaryReassociate.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/NaryReassociate.cpp +++ llvm/trunk/lib/Transforms/Scalar/NaryReassociate.cpp @@ -208,7 +208,7 @@ } bool NaryReassociate::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; AC = &getAnalysis().getAssumptionCache(F); Index: llvm/trunk/lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/Reassociate.cpp +++ llvm/trunk/lib/Transforms/Scalar/Reassociate.cpp @@ -2257,7 +2257,7 @@ } bool Reassociate::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; // Reassociate needs for each instruction to have its operands already Index: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp +++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp @@ -1568,7 +1568,7 @@ // 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 @@ } bool IPSCCP::runOnModule(Module &M) { + if (skipModule(M)) + return false; + const DataLayout &DL = M.getDataLayout(); const TargetLibraryInfo *TLI = &getAnalysis().getTLI(); Index: llvm/trunk/lib/Transforms/Scalar/SROA.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/SROA.cpp +++ llvm/trunk/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::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 @@ initializeSROALegacyPassPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; auto PA = Impl.runImpl( Index: llvm/trunk/lib/Transforms/Scalar/ScalarReplAggregates.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/ScalarReplAggregates.cpp +++ llvm/trunk/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -1026,7 +1026,7 @@ bool SROA::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; bool Changed = performPromotion(F); Index: llvm/trunk/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp +++ llvm/trunk/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp @@ -1064,7 +1064,7 @@ } bool SeparateConstOffsetFromGEP::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; if (DisableSeparateConstOffsetFromGEP) Index: llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ llvm/trunk/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 @@ 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 @@ if (PredicateFtor && !PredicateFtor(F)) return false; - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; AssumptionCache *AC = Index: llvm/trunk/lib/Transforms/Scalar/SpeculativeExecution.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/SpeculativeExecution.cpp +++ llvm/trunk/lib/Transforms/Scalar/SpeculativeExecution.cpp @@ -141,7 +141,7 @@ } bool SpeculativeExecution::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; TTI = &getAnalysis().getTTI(F); Index: llvm/trunk/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp +++ llvm/trunk/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp @@ -682,7 +682,7 @@ } bool StraightLineStrengthReduce::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; TTI = &getAnalysis().getTTI(F); Index: llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -157,7 +157,7 @@ } bool TailCallElim::runOnFunction(Function &F) { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true") Index: llvm/trunk/lib/Transforms/Utils/Mem2Reg.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/Mem2Reg.cpp +++ llvm/trunk/lib/Transforms/Utils/Mem2Reg.cpp @@ -59,13 +59,13 @@ 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(); Index: llvm/trunk/lib/Transforms/Vectorize/BBVectorize.cpp =================================================================== --- llvm/trunk/lib/Transforms/Vectorize/BBVectorize.cpp +++ llvm/trunk/lib/Transforms/Vectorize/BBVectorize.cpp @@ -397,7 +397,7 @@ 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() << Index: llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp +++ llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -1707,6 +1707,9 @@ BlockFrequency ColdEntryFreq; bool runOnFunction(Function &F) override { + if (skipFunction(F)) + return false; + SE = &getAnalysis().getSE(); LI = &getAnalysis().getLoopInfo(); TTI = &getAnalysis().getTTI(F); Index: llvm/trunk/lib/Transforms/Vectorize/SLPVectorizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ llvm/trunk/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -3396,7 +3396,7 @@ } bool runOnFunction(Function &F) override { - if (skipOptnoneFunction(F)) + if (skipFunction(F)) return false; SE = &getAnalysis().getSE(); Index: llvm/trunk/test/Other/opt-bisect-helper.py =================================================================== --- llvm/trunk/test/Other/opt-bisect-helper.py +++ llvm/trunk/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) Index: llvm/trunk/test/Other/opt-bisect-legacy-pass-manager.ll =================================================================== --- llvm/trunk/test/Other/opt-bisect-legacy-pass-manager.ll +++ llvm/trunk/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 +} Index: llvm/trunk/test/Other/opt-bisect-new-pass-manager.ll =================================================================== --- llvm/trunk/test/Other/opt-bisect-new-pass-manager.ll +++ llvm/trunk/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 +}