OSDN Git Service

Initial implementation of optimization bisect support.
authorAndrew Kaylor <andrew.kaylor@intel.com>
Thu, 21 Apr 2016 17:58:54 +0000 (17:58 +0000)
committerAndrew Kaylor <andrew.kaylor@intel.com>
Thu, 21 Apr 2016 17:58:54 +0000 (17:58 +0000)
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

98 files changed:
include/llvm/Analysis/CallGraphSCCPass.h
include/llvm/Analysis/LazyCallGraph.h
include/llvm/Analysis/LoopPass.h
include/llvm/IR/LLVMContext.h
include/llvm/IR/OptBisect.h [new file with mode: 0644]
include/llvm/Pass.h
lib/Analysis/CallGraphSCCPass.cpp
lib/Analysis/LoopPass.cpp
lib/CodeGen/BranchFolding.cpp
lib/CodeGen/CodeGenPrepare.cpp
lib/CodeGen/DeadMachineInstructionElim.cpp
lib/CodeGen/LowerEmuTLS.cpp
lib/CodeGen/MachineBlockPlacement.cpp
lib/CodeGen/MachineCSE.cpp
lib/CodeGen/MachineCopyPropagation.cpp
lib/CodeGen/MachineLICM.cpp
lib/CodeGen/MachineScheduler.cpp
lib/CodeGen/MachineSink.cpp
lib/CodeGen/OptimizePHIs.cpp
lib/CodeGen/PeepholeOptimizer.cpp
lib/CodeGen/PostRASchedulerList.cpp
lib/CodeGen/StackColoring.cpp
lib/CodeGen/TailDuplication.cpp
lib/IR/CMakeLists.txt
lib/IR/LLVMContext.cpp
lib/IR/LLVMContextImpl.cpp
lib/IR/LLVMContextImpl.h
lib/IR/OptBisect.cpp [new file with mode: 0644]
lib/IR/Pass.cpp
lib/Transforms/IPO/ArgumentPromotion.cpp
lib/Transforms/IPO/ConstantMerge.cpp
lib/Transforms/IPO/CrossDSOCFI.cpp
lib/Transforms/IPO/DeadArgumentElimination.cpp
lib/Transforms/IPO/ElimAvailExtern.cpp
lib/Transforms/IPO/ExtractGV.cpp
lib/Transforms/IPO/FunctionAttrs.cpp
lib/Transforms/IPO/FunctionImport.cpp
lib/Transforms/IPO/GlobalDCE.cpp
lib/Transforms/IPO/GlobalOpt.cpp
lib/Transforms/IPO/IPConstantPropagation.cpp
lib/Transforms/IPO/InferFunctionAttrs.cpp
lib/Transforms/IPO/Inliner.cpp
lib/Transforms/IPO/Internalize.cpp
lib/Transforms/IPO/LoopExtractor.cpp
lib/Transforms/IPO/LowerBitSets.cpp
lib/Transforms/IPO/MergeFunctions.cpp
lib/Transforms/IPO/PartialInlining.cpp
lib/Transforms/IPO/PruneEH.cpp
lib/Transforms/IPO/StripDeadPrototypes.cpp
lib/Transforms/IPO/StripSymbols.cpp
lib/Transforms/IPO/WholeProgramDevirt.cpp
lib/Transforms/InstCombine/InstructionCombining.cpp
lib/Transforms/Instrumentation/PGOInstrumentation.cpp
lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
lib/Transforms/Scalar/ADCE.cpp
lib/Transforms/Scalar/BDCE.cpp
lib/Transforms/Scalar/ConstantHoisting.cpp
lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
lib/Transforms/Scalar/DCE.cpp
lib/Transforms/Scalar/DeadStoreElimination.cpp
lib/Transforms/Scalar/EarlyCSE.cpp
lib/Transforms/Scalar/Float2Int.cpp
lib/Transforms/Scalar/GVN.cpp
lib/Transforms/Scalar/IndVarSimplify.cpp
lib/Transforms/Scalar/JumpThreading.cpp
lib/Transforms/Scalar/LICM.cpp
lib/Transforms/Scalar/LoadCombine.cpp
lib/Transforms/Scalar/LoopDeletion.cpp
lib/Transforms/Scalar/LoopIdiomRecognize.cpp
lib/Transforms/Scalar/LoopInstSimplify.cpp
lib/Transforms/Scalar/LoopLoadElimination.cpp
lib/Transforms/Scalar/LoopRerollPass.cpp
lib/Transforms/Scalar/LoopRotation.cpp
lib/Transforms/Scalar/LoopSimplifyCFG.cpp
lib/Transforms/Scalar/LoopStrengthReduce.cpp
lib/Transforms/Scalar/LoopUnrollPass.cpp
lib/Transforms/Scalar/LoopUnswitch.cpp
lib/Transforms/Scalar/LoopVersioningLICM.cpp
lib/Transforms/Scalar/LowerAtomic.cpp
lib/Transforms/Scalar/MemCpyOptimizer.cpp
lib/Transforms/Scalar/MergedLoadStoreMotion.cpp
lib/Transforms/Scalar/NaryReassociate.cpp
lib/Transforms/Scalar/Reassociate.cpp
lib/Transforms/Scalar/SCCP.cpp
lib/Transforms/Scalar/SROA.cpp
lib/Transforms/Scalar/ScalarReplAggregates.cpp
lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
lib/Transforms/Scalar/SimplifyCFGPass.cpp
lib/Transforms/Scalar/SpeculativeExecution.cpp
lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
lib/Transforms/Scalar/TailRecursionElimination.cpp
lib/Transforms/Utils/Mem2Reg.cpp
lib/Transforms/Vectorize/BBVectorize.cpp
lib/Transforms/Vectorize/LoopVectorize.cpp
lib/Transforms/Vectorize/SLPVectorizer.cpp
test/Other/opt-bisect-helper.py [new file with mode: 0755]
test/Other/opt-bisect-legacy-pass-manager.ll [new file with mode: 0644]
test/Other/opt-bisect-new-pass-manager.ll [new file with mode: 0644]

index 9c7f7bd..fd9ea56 100644 (file)
@@ -77,15 +77,21 @@ public:
   /// the call graph.  If the derived class implements this method, it should
   /// always explicitly call the implementation here.
   void getAnalysisUsage(AnalysisUsage &Info) const override;
+
+protected:
+  /// Optional passes call this function to check whether the pass should be
+  /// skipped. This is the case when optimization bisect is over the limit.
+  bool skipSCC(CallGraphSCC &SCC) const;
 };
 
 /// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
 class CallGraphSCC {
+  const CallGraph &CG; // The call graph for this SCC.
   void *Context; // The CGPassManager object that is vending this.
   std::vector<CallGraphNode*> Nodes;
 
 public:
-  CallGraphSCC(void *context) : Context(context) {}
+  CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {}
 
   void initialize(CallGraphNode *const *I, CallGraphNode *const *E) {
     Nodes.assign(I, E);
@@ -101,6 +107,8 @@ public:
   typedef std::vector<CallGraphNode *>::const_iterator iterator;
   iterator begin() const { return Nodes.begin(); }
   iterator end() const { return Nodes.end(); }
+
+  const CallGraph &getCallGraph() { return CG; }
 };
 
 } // End llvm namespace
index 4e72052..b3e919d 100644 (file)
@@ -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
index 2cf734e..89debec 100644 (file)
@@ -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 {
index 1d05269..8f13171 100644 (file)
@@ -32,6 +32,7 @@ class DiagnosticInfo;
 template <typename T> class SmallVectorImpl;
 class Function;
 class DebugLoc;
+class OptBisect;
 
 /// This is an important class for using LLVM in a threaded context.  It
 /// (opaquely) owns and manages the core "global" data of LLVM's core
@@ -226,6 +227,9 @@ public:
     return OptionRegistry::instance().template get<ValT, Base, Mem>();
   }
 
+  /// \brief Access the object which manages optimization bisection for failure
+  /// analysis.
+  OptBisect &getOptBisect();
 private:
   LLVMContext(LLVMContext&) = delete;
   void operator=(LLVMContext&) = delete;
diff --git a/include/llvm/IR/OptBisect.h b/include/llvm/IR/OptBisect.h
new file mode 100644 (file)
index 0000000..d4c8fcf
--- /dev/null
@@ -0,0 +1,139 @@
+//===----------- llvm/IR/OptBisect.h - LLVM Bisect support -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares the interface for bisecting optimizations.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_OPTBISECT_H
+#define LLVM_IR_OPTBISECT_H
+
+namespace llvm {
+
+class Pass;
+class StringRef;
+class Twine;
+
+/// This class implements a mechanism to disable passes and individual
+/// optimizations at compile time based on a command line option
+/// (-opt-bisect-limit) in order to perform a bisecting search for
+/// optimization-related problems.
+class OptBisect {
+public:
+  /// \brief Default constructor, initializes the OptBisect state based on the
+  /// -opt-bisect-limit command line argument.
+  ///
+  /// By default, bisection is disabled.
+  ///
+  /// Clients should not instantiate this class directly.  All access should go
+  /// through LLVMContext.
+  OptBisect();
+
+  /// Checks the bisect limit to determine if the specified pass should run.
+  ///
+  /// This function will immediate return true if bisection is disabled. If the
+  /// bisect limit is set to -1, the function will print a message describing
+  /// the pass and the bisect number assigned to it and return true.  Otherwise,
+  /// the function will print a message with the bisect number assigned to the
+  /// pass and indicating whether or not the pass will be run and return true if
+  /// the bisect limit has not yet been exceded or false if it has.
+  ///
+  /// Most passes should not call this routine directly.  Instead, it is called
+  /// through a helper routine provided by the pass base class.  For instance,
+  /// function passes should call FunctionPass::skipFunction().
+  template <class UnitT>
+  bool shouldRunPass(const Pass *P, const UnitT &U);
+
+  /// Checks the bisect limit to determine if the specified pass should run.
+  ///
+  /// This function will immediate return true if bisection is disabled. If the
+  /// bisect limit is set to -1, the function will print a message describing
+  /// the pass and the bisect number assigned to it and return true.  Otherwise,
+  /// the function will print a message with the bisect number assigned to the
+  /// pass and indicating whether or not the pass will be run and return true if
+  /// the bisect limit has not yet been exceded or false if it has.
+  ///
+  /// In order to avoid duplicating the code necessary to access OptBisect
+  /// through the LLVMContext class, passes may call one of the helper
+  /// functions that get the context from an IR object.  For instance,
+  /// function passes may call skipPassForFunction().
+  template <class UnitT>
+  bool shouldRunPass(const StringRef PassName, const UnitT &U);
+
+  /// Checks the bisect limit to determine if the optimization described by the
+  /// /p Desc argument should run.
+  ///
+  /// This function will immediate return true if bisection is disabled. If the
+  /// bisect limit is set to -1, the function will print a message with the
+  /// bisect number assigned to the optimization along with the /p Desc
+  /// description and return true.  Otherwise, the function will print a message
+  /// with the bisect number assigned to the optimization and indicating whether
+  /// or not the pass will be run and return true if the bisect limit has not
+  /// yet been exceded or false if it has.
+  ///
+  /// Passes may call this function to provide more fine grained control over
+  /// individual optimizations performed by the pass.  Passes which cannot be
+  /// skipped entirely (such as non-optional code generation passes) may still
+  /// call this function to control whether or not individual optional
+  /// transformations are performed.
+  bool shouldRunCase(const Twine &Desc);
+
+private:
+  bool checkPass(const StringRef PassName, const StringRef TargetDesc);
+
+  bool BisectEnabled = false;
+  unsigned LastBisectNum = 0;
+};
+
+// Access to OptBisect should go through LLVMContext, but for the
+// new pass manager there is no single base class from which a
+// helper function to abstract the messy details can be provided.
+// Instead, we provide standalone helper functions for each IR
+// type that must be handled.
+
+class Module;
+class Function;
+//class BasicBlock;
+//class Loop;
+
+/// Check with the OptBisect object to determine whether the described pass
+/// should be skipped.
+///
+/// This is a helper function which abstracts the details of accessing OptBisect
+/// through an LLVMContext obtained from a Module.
+bool skipPassForModule(const StringRef PassName, const Module &M);
+
+/// Check with the OptBisect object to determine whether the described pass
+/// should be skipped.
+///
+/// This is a helper function which abstracts the details of accessing OptBisect
+/// through an LLVMContext obtained from a Function.
+bool skipPassForFunction(const StringRef PassName, const Function &F);
+#if 0
+/// Check with the OptBisect object to determine whether the described pass
+/// should be skipped.
+///
+/// This is a helper function which abstracts the details of accessing OptBisect
+/// through an LLVMContext obtained from a BasicBlock.
+bool skipPassForBasicBlock(const StringRef PassName, const BasicBlock &BB);
+
+/// Check with the OptBisect object to determine whether the described pass
+/// should be skipped.
+///
+/// This is a helper function which abstracts the details of accessing OptBisect
+/// through an LLVMContext obtained from a Loop.
+bool skipPassForLoop(const StringRef PassName, const Loop &L);
+#endif
+// skiPassForSCC is declared in LazyCallGraph.h because of include file
+// dependency issues related to LazyCallGraph::SCC being nested.
+
+} // end namespace llvm
+
+#endif // LLVM_IR_OPTBISECT_H
index 99604cd..7fcdcbc 100644 (file)
@@ -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
index 6dd1d0a..71226bd 100644 (file)
@@ -23,6 +23,7 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/LegacyPassManagers.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Timer.h"
@@ -444,7 +445,7 @@ bool CGPassManager::runOnModule(Module &M) {
   // Walk the callgraph in bottom-up SCC order.
   scc_iterator<CallGraph*> CGI = scc_begin(&CG);
 
-  CallGraphSCC CurSCC(&CGI);
+  CallGraphSCC CurSCC(CG, &CGI);
   while (!CGI.isAtEnd()) {
     // Copy the current SCC and increment past it so that the pass can hack
     // on the SCC if it wants to without invalidating our iterator.
@@ -631,3 +632,9 @@ Pass *CallGraphSCCPass::createPrinterPass(raw_ostream &O,
   return new PrintCallGraphPass(Banner, O);
 }
 
+bool CallGraphSCCPass::skipSCC(CallGraphSCC &SCC) const {
+  return !SCC.getCallGraph().getModule()
+              .getContext()
+              .getOptBisect()
+              .shouldRunPass(this, SCC);
+}
index 8163231..3181e4f 100644 (file)
@@ -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");
index 065bac0..d0b2304 100644 (file)
@@ -90,7 +90,7 @@ INITIALIZE_PASS(BranchFolderPass, "branch-folder",
                 "Control Flow Optimizer", false, false)
 
 bool BranchFolderPass::runOnMachineFunction(MachineFunction &MF) {
-  if (skipOptnoneFunction(*MF.getFunction()))
+  if (skipFunction(*MF.getFunction()))
     return false;
 
   TargetPassConfig *PassConfig = &getAnalysis<TargetPassConfig>();
index ea1325a..e34233a 100644 (file)
@@ -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();
index b11b497..ae58b5b 100644 (file)
@@ -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;
index 0b9a501..6966c8c 100644 (file)
@@ -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;
 
index af78d8a..6a9078a 100644 (file)
@@ -1430,7 +1430,7 @@ bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &F) {
   if (std::next(F.begin()) == F.end())
     return false;
 
-  if (skipOptnoneFunction(*F.getFunction()))
+  if (skipFunction(*F.getFunction()))
     return false;
 
   MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
index c602b51..b8283ea 100644 (file)
@@ -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();
index 3fdf16f..7f2e778 100644 (file)
@@ -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;
index 99a97d2..7d0221f 100644 (file)
@@ -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;
index e4d1c3c..9e28ed9 100644 (file)
@@ -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()) {
index 07fbd3d..c42281b 100644 (file)
@@ -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");
index a1042e7..0177e41 100644 (file)
@@ -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();
index 52b42b6..3556150 100644 (file)
@@ -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");
index ad9f946..79958c9 100644 (file)
@@ -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();
index d7ad48e..d93fc6a 100644 (file)
@@ -657,7 +657,7 @@ void StackColoring::expungeSlotMap(DenseMap<int, int> &SlotRemap,
 }
 
 bool StackColoring::runOnMachineFunction(MachineFunction &Func) {
-  if (skipOptnoneFunction(*Func.getFunction()))
+  if (skipFunction(*Func.getFunction()))
     return false;
 
   DEBUG(dbgs() << "********** Stack Coloring **********\n"
index 4831c6a..2b1fb12 100644 (file)
@@ -44,7 +44,7 @@ INITIALIZE_PASS(TailDuplicatePass, "tailduplication", "Tail Duplication", false,
                 false)
 
 bool TailDuplicatePass::runOnMachineFunction(MachineFunction &MF) {
-  if (skipOptnoneFunction(*MF.getFunction()))
+  if (skipFunction(*MF.getFunction()))
     return false;
 
   auto MMI = getAnalysisIfAvailable<MachineModuleInfo>();
index 554ea14..f3f8733 100644 (file)
@@ -39,6 +39,7 @@ add_llvm_library(LLVMCore
   Module.cpp
   ModuleSummaryIndex.cpp
   Operator.cpp
+  OptBisect.cpp
   Pass.cpp
   PassManager.cpp
   PassRegistry.cpp
index 45c2806..ee95c4f 100644 (file)
@@ -325,3 +325,7 @@ void LLVMContext::disableDebugTypeODRUniquing() { pImpl->DITypeMap.reset(); }
 void LLVMContext::setDiscardValueNames(bool Discard) {
   pImpl->DiscardValueNames = Discard;
 }
+
+OptBisect &LLVMContext::getOptBisect() {
+  return pImpl->getOptBisect();
+}
index d5d9038..d27fcb1 100644 (file)
@@ -16,6 +16,8 @@
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/OptBisect.h"
+#include "llvm/Support/ManagedStatic.h"
 #include <algorithm>
 using namespace llvm;
 
@@ -232,3 +234,19 @@ void GetElementPtrConstantExpr::anchor() { }
 
 void CompareConstantExpr::anchor() { }
 
+/// Singleton instance of the OptBisect class.
+///
+/// This singleton is accessed via the LLVMContext::getOptBisect() function.  It
+/// provides a mechanism to disable passes and individual optimizations at
+/// compile time based on a command line option (-opt-bisect-limit) in order to
+/// perform a bisecting search for optimization-related problems.
+///
+/// Even if multiple LLVMContext objects are created, they will all return the
+/// same instance of OptBisect in order to provide a single bisect count.  Any
+/// code that uses the OptBisect object should be serialized when bisection is
+/// enabled in order to enable a consistent bisect count.
+static ManagedStatic<OptBisect> OptBisector;
+
+OptBisect &LLVMContextImpl::getOptBisect() {
+  return *OptBisector;
+}
index 0d6d979..a4d7b7e 100644 (file)
@@ -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 (file)
index 0000000..d06f40f
--- /dev/null
@@ -0,0 +1,176 @@
+//===------- llvm/IR/OptBisect/Bisect.cpp - LLVM Bisect support --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements support for a bisecting optimizations based on a
+/// command line option.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/CallGraphSCCPass.h"
+#include "llvm/Analysis/LazyCallGraph.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/OptBisect.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden,
+                                   cl::init(INT_MAX), cl::Optional,
+                                   cl::desc("Maximum optimization to perform"));
+
+OptBisect::OptBisect() {
+  BisectEnabled = OptBisectLimit != INT_MAX;
+}
+
+static void printPassMessage(const StringRef &Name, int PassNum,
+                             StringRef TargetDesc, bool Running) {
+  StringRef Status = Running ? "" : "NOT ";
+  errs() << "BISECT: " << Status << "running pass "
+         << "(" << PassNum << ") " << Name << " on " << TargetDesc << "\n";
+}
+
+static void printCaseMessage(int CaseNum, StringRef Msg, bool Running) {
+  if (Running)
+    errs() << "BISECT: running case (";
+  else
+    errs() << "BISECT: NOT running case (";
+  errs() << CaseNum << "): " << Msg << "\n";
+}
+
+static std::string getDescription(const Module &M) {
+  return "module (" + M.getName().str() + ")";
+}
+
+static std::string getDescription(const Function &F) {
+  return "function (" + F.getName().str() + ")";
+}
+
+static std::string getDescription(const BasicBlock &BB) {
+  return "basic block (" + BB.getName().str() + ") in function (" +
+         BB.getParent()->getName().str() + ")";
+}
+
+static std::string getDescription(const Loop &L) {
+  // FIXME: I'd like to be able to provide a better description here, but
+  //        calling L->getHeader() would introduce a new dependency on the
+  //        LLVMCore library.
+  return "loop";
+}
+
+static std::string getDescription(const CallGraphSCC &SCC) {
+  std::string Desc = "SCC (";
+  bool First = true;
+  for (CallGraphNode *CGN : SCC) {
+    if (First)
+      First = false;
+    else
+      Desc += ", ";
+    Function *F = CGN->getFunction();
+    if (F)
+      Desc += F->getName();
+    else
+      Desc += "<<null function>>";
+  }
+  Desc += ")";
+  return Desc;
+}
+
+static std::string getDescription(const LazyCallGraph::SCC &SCC) {
+  std::string Desc = "SCC (";
+  bool First = true;
+  for (LazyCallGraph::Node &CGN : SCC) {
+    if (First)
+      First = false;
+    else
+      Desc += ", ";
+    Function &F = CGN.getFunction();
+    Desc += F.getName();
+  }
+  Desc += ")";
+  return Desc;
+}
+
+// Force instantiations.
+template bool OptBisect::shouldRunPass(const Pass *, const Module &);
+template bool OptBisect::shouldRunPass(const Pass *, const Function &);
+template bool OptBisect::shouldRunPass(const Pass *, const BasicBlock &);
+template bool OptBisect::shouldRunPass(const Pass *, const Loop &);
+template bool OptBisect::shouldRunPass(const Pass *, const CallGraphSCC &);
+template bool OptBisect::shouldRunPass(const StringRef PassName,
+                                       const Module &);
+template bool OptBisect::shouldRunPass(const StringRef PassName,
+                                       const Function &);
+template bool OptBisect::shouldRunPass(const StringRef PassName,
+                                       const BasicBlock &);
+template bool OptBisect::shouldRunPass(const StringRef PassName, const Loop &);
+template bool OptBisect::shouldRunPass(const StringRef PassName,
+                                       const LazyCallGraph::SCC &);
+
+template <class UnitT>
+bool OptBisect::shouldRunPass(const Pass *P, const UnitT &U) {
+  if (!BisectEnabled)
+    return true;
+  return checkPass(P->getPassName(), getDescription(U));
+}
+
+// Interface function for the new pass manager.
+template <class UnitT>
+bool OptBisect::shouldRunPass(const StringRef PassName, const UnitT &U) {
+  if (!BisectEnabled)
+    return true;
+  return checkPass(PassName, getDescription(U));
+}
+
+bool OptBisect::checkPass(const StringRef PassName,
+                          const StringRef TargetDesc) {
+  assert(BisectEnabled);
+
+  int CurBisectNum = ++LastBisectNum;
+  bool ShouldRun = (OptBisectLimit == -1 || CurBisectNum <= OptBisectLimit);
+  printPassMessage(PassName, CurBisectNum, TargetDesc, ShouldRun);
+  return ShouldRun;
+}
+
+bool OptBisect::shouldRunCase(const Twine &Msg) {
+  if (!BisectEnabled)
+    return true;
+  int CurFuelNum = ++LastBisectNum;
+  bool ShouldRun = (OptBisectLimit == -1 || CurFuelNum <= OptBisectLimit);
+  printCaseMessage(CurFuelNum, Msg.str(), ShouldRun);
+  return ShouldRun;
+}
+
+bool llvm::skipPassForModule(const StringRef PassName, const Module &M) {
+  return !M.getContext().getOptBisect().shouldRunPass(PassName, M);
+}
+
+bool llvm::skipPassForFunction(const StringRef PassName, const Function &F) {
+  return !F.getContext().getOptBisect().shouldRunPass(PassName, F);
+}
+#if 0
+bool llvm::skipPassForBasicBlock(const StringRef PassName, const BasicBlock &BB) {
+  return !BB.getContext().getOptBisect().shouldRunPass(PassName, BB);
+}
+
+bool llvm::skipPassForLoop(const StringRef PassName, const Loop &L) {
+  const Function *F = L.getHeader()->getParent();
+  if (!F)
+    return false;
+  return !F->getContext().getOptBisect().shouldRunPass(PassName, L);
+}
+#endif
+bool llvm::skipPassForSCC(const StringRef PassName, const LazyCallGraph::SCC &SCC) {
+  LLVMContext &Context = SCC.begin()->getFunction().getContext();
+  return !Context.getOptBisect().shouldRunPass(PassName, SCC);
+}
+
index 8ce6559..69299fe 100644 (file)
@@ -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()
index 1c0f590..8823b81 100644 (file)
@@ -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.
index 0aa49d6..87f35fd 100644 (file)
@@ -96,6 +96,8 @@ unsigned ConstantMerge::getAlignment(GlobalVariable *GV) const {
 }
 
 bool ConstantMerge::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
 
   // Find all the globals that are marked "used".  These cannot be merged.
   SmallPtrSet<const GlobalValue*, 8> UsedGlobals;
index 9cf57dc..4c62cbe 100644 (file)
@@ -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();
index 27379be..3ca5acd 100644 (file)
@@ -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 "..."
index af313a6..083debc 100644 (file)
@@ -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.
index 23e5177..e1bd676 100644 (file)
@@ -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("");
index ec6062a..a9a2db1 100644 (file)
@@ -987,6 +987,9 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
 
 PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
                                                   CGSCCAnalysisManager &AM) {
+  if (skipPassForSCC(name(), C))
+    return PreservedAnalyses::all();
+
   Module &M = *C.begin()->getFunction().getParent();
   const ModuleAnalysisManager &MAM =
       AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
@@ -1081,6 +1084,9 @@ INITIALIZE_PASS_END(PostOrderFunctionAttrsLegacyPass, "functionattrs",
 Pass *llvm::createPostOrderFunctionAttrsLegacyPass() { return new PostOrderFunctionAttrsLegacyPass(); }
 
 bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) {
+  if (skipSCC(SCC))
+    return false;
+
   TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
   bool Changed = false;
 
@@ -1195,6 +1201,9 @@ static bool addNoRecurseAttrsTopDown(Function &F) {
 }
 
 bool ReversePostOrderFunctionAttrs::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   // We only have a post-order SCC traversal (because SCCs are inherently
   // discovered in post-order), so we accumulate them in a vector and then walk
   // it in reverse. This is simpler than using the RPO iterator infrastructure
index 25d4130..cb8d633 100644 (file)
@@ -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");
index 531aa4d..63d3032 100644 (file)
@@ -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.
index 60d1e7c..a9c2a95 100644 (file)
@@ -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();
index 060aac1..a1533b3 100644 (file)
@@ -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;
 
index 030a646..02fc1f6 100644 (file)
@@ -14,6 +14,7 @@
 #include "llvm/IR/Function.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
@@ -955,6 +956,9 @@ static bool inferAllPrototypeAttributes(Module &M,
 
 PreservedAnalyses InferFunctionAttrsPass::run(Module &M,
                                               AnalysisManager<Module> &AM) {
+  if (skipPassForModule(name(), M))
+    return PreservedAnalyses::all();
+
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(M);
 
   if (!inferAllPrototypeAttributes(M, TLI))
@@ -979,6 +983,9 @@ struct InferFunctionAttrsLegacyPass : public ModulePass {
   }
 
   bool runOnModule(Module &M) override {
+    if (skipModule(M))
+      return false;
+
     auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
     return inferAllPrototypeAttributes(M, TLI);
   }
index 2c696cc..d598c5f 100644 (file)
@@ -356,6 +356,9 @@ static bool InlineHistoryIncludes(Function *F, int InlineHistoryID,
 }
 
 bool Inliner::runOnSCC(CallGraphSCC &SCC) {
+  if (skipSCC(SCC))
+    return false;
+
   CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
   ACT = &getAnalysis<AssumptionCacheTracker>();
   auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
index ca868e9..6db826f 100644 (file)
@@ -105,6 +105,9 @@ public:
   }
 
   bool runOnModule(Module &M) override {
+    if (skipModule(M))
+      return false;
+
     CallGraphWrapperPass *CGPass =
         getAnalysisIfAvailable<CallGraphWrapperPass>();
     CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr;
index 3c6a7bb..7578e6a 100644 (file)
@@ -81,7 +81,7 @@ INITIALIZE_PASS(SingleLoopExtractor, "loop-extract-single",
 Pass *llvm::createLoopExtractorPass() { return new LoopExtractor(); }
 
 bool LoopExtractor::runOnLoop(Loop *L, LPPassManager &) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   // Only visit top-level loops.
@@ -249,6 +249,9 @@ void BlockExtractorPass::SplitLandingPadPreds(Function *F) {
 }
 
 bool BlockExtractorPass::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   std::set<BasicBlock*> TranslatedBlocksToNotExtract;
   for (unsigned i = 0, e = BlocksToNotExtract.size(); i != e; ++i) {
     BasicBlock *BB = BlocksToNotExtract[i];
index db5bab0..78981fd 100644 (file)
@@ -1051,6 +1051,9 @@ bool LowerBitSets::eraseBitSetMetadata() {
 }
 
 bool LowerBitSets::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   bool Changed = buildBitSets();
   Changed |= eraseBitSetMetadata();
   return Changed;
index 4e27898..e16749c 100644 (file)
@@ -1525,6 +1525,9 @@ bool MergeFunctions::doSanityCheck(std::vector<WeakVH> &Worklist) {
 }
 
 bool MergeFunctions::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   bool Changed = false;
 
   // All functions in the module, ordered by hash. Functions with a unique
index 0c5c84b..7b1b098 100644 (file)
@@ -149,6 +149,9 @@ Function* PartialInliner::unswitchFunction(Function* F) {
 }
 
 bool PartialInliner::runOnModule(Module& M) {
+  if (skipModule(M))
+    return false;
+
   std::vector<Function*> worklist;
   worklist.reserve(M.size());
   for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
index 940f97b..04383f4 100644 (file)
@@ -63,6 +63,9 @@ Pass *llvm::createPruneEHPass() { return new PruneEH(); }
 
 
 bool PruneEH::runOnSCC(CallGraphSCC &SCC) {
+  if (skipSCC(SCC))
+    return false;
+
   SmallPtrSet<CallGraphNode *, 8> SCCNodes;
   CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
   bool MadeChange = false;
index c94cc7c..2ac854f 100644 (file)
@@ -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);
   }
 };
index 6459542..3202837 100644 (file)
@@ -229,6 +229,9 @@ static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) {
 }
 
 bool StripSymbols::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   bool Changed = false;
   Changed |= StripDebugInfo(M);
   if (!OnlyDebugInfo)
@@ -237,10 +240,15 @@ bool StripSymbols::runOnModule(Module &M) {
 }
 
 bool StripNonDebugSymbols::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   return StripSymbolNames(M, true);
 }
 
 bool StripDebugDeclare::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
 
   Function *Declare = M.getFunction("llvm.dbg.declare");
   std::vector<Constant*> DeadConstants;
@@ -286,6 +294,9 @@ bool StripDebugDeclare::runOnModule(Module &M) {
 /// optimized away by the optimizer. This special pass removes debug info for
 /// such symbols.
 bool StripDeadDebugInfo::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   bool Changed = false;
 
   LLVMContext &C = M.getContext();
index 48b05b6..e7c161d 100644 (file)
@@ -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
index 3eebf5b..8a9d282 100644 (file)
@@ -56,6 +56,7 @@
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/GetElementPtrTypeIterator.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/ValueHandle.h"
 #include "llvm/Support/CommandLine.h"
@@ -3088,6 +3089,9 @@ combineInstructionsOverFunction(Function &F, InstCombineWorklist &Worklist,
 
 PreservedAnalyses InstCombinePass::run(Function &F,
                                        AnalysisManager<Function> &AM) {
+  if (skipPassForFunction(name(), F))
+    return PreservedAnalyses::all();
+
   auto &AC = AM.getResult<AssumptionAnalysis>(F);
   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
@@ -3120,7 +3124,7 @@ void InstructionCombiningPass::getAnalysisUsage(AnalysisUsage &AU) const {
 }
 
 bool InstructionCombiningPass::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   // Required analyses.
index bf2933e..ebfb954 100644 (file)
@@ -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.
index 1bb0739..b2c62a0 100644 (file)
@@ -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
index 579e60f..34e15a1 100644 (file)
@@ -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);
   }
index a27eab8..a357280 100644 (file)
@@ -59,7 +59,7 @@ INITIALIZE_PASS_END(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",
                     false, false)
 
 bool BDCE::runOnFunction(Function& F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
   auto &DB = getAnalysis<DemandedBitsWrapperPass>().getDemandedBits();
 
index d549228..74050fa 100644 (file)
@@ -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");
index 8f30d5b..0125471 100644 (file)
@@ -399,7 +399,7 @@ Constant *CorrelatedValuePropagation::getConstantAt(Value *V, Instruction *At) {
 }
 
 bool CorrelatedValuePropagation::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   LVI = &getAnalysis<LazyValueInfo>();
index b67c3c7..a1f2ecf 100644 (file)
@@ -41,7 +41,7 @@ namespace {
       initializeDeadInstEliminationPass(*PassRegistry::getPassRegistry());
     }
     bool runOnBasicBlock(BasicBlock &BB) override {
-      if (skipOptnoneFunction(BB))
+      if (skipBasicBlock(BB))
         return false;
       auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
       TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI() : nullptr;
@@ -122,7 +122,7 @@ static bool DCEInstruction(Instruction *I,
 }
 
 bool DCE::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
index 61bbdf0..ee0905c 100644 (file)
@@ -58,7 +58,7 @@ namespace {
     }
 
     bool runOnFunction(Function &F) override {
-      if (skipOptnoneFunction(F))
+      if (skipFunction(F))
         return false;
 
       AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
index af0c0ac..7be3aab 100644 (file)
@@ -25,6 +25,7 @@
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Debug.h"
@@ -819,6 +820,9 @@ bool EarlyCSE::run() {
 
 PreservedAnalyses EarlyCSEPass::run(Function &F,
                                     AnalysisManager<Function> &AM) {
+  if (skipPassForFunction(name(), F))
+    return PreservedAnalyses::all();
+
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
   auto &TTI = AM.getResult<TargetIRAnalysis>(F);
   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
@@ -853,7 +857,7 @@ public:
   }
 
   bool runOnFunction(Function &F) override {
-    if (skipOptnoneFunction(F))
+    if (skipFunction(F))
       return false;
 
     auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
index 3c63510..0a41187 100644 (file)
@@ -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");
index 303785f..02e18ab 100644 (file)
@@ -43,6 +43,7 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Metadata.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
@@ -584,6 +585,9 @@ void GVN::ValueTable::verifyRemoved(const Value *V) const {
 //===----------------------------------------------------------------------===//
 
 PreservedAnalyses GVN::run(Function &F, AnalysisManager<Function> &AM) {
+  if (skipPassForFunction(name(), F))
+    return PreservedAnalyses::all();
+
   // FIXME: The order of evaluation of these 'getResult' calls is very
   // significant! Re-ordering these variables will cause GVN when run alone to
   // be less effective! We should fix memdep and basic-aa to not exhibit this
@@ -2675,7 +2679,7 @@ public:
   }
 
   bool runOnFunction(Function &F) override {
-    if (skipOptnoneFunction(F))
+    if (skipFunction(F))
       return false;
 
     return Impl.runImpl(
index 899aa1e..effb8f6 100644 (file)
@@ -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:
index 7495baa..ba406a8 100644 (file)
@@ -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");
index 331cd2d..72f0416 100644 (file)
@@ -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;
index 354a3da..a54cd88 100644 (file)
@@ -221,7 +221,7 @@ bool LoadCombine::combineLoads(SmallVectorImpl<LoadPOPPair> &Loads) {
 }
 
 bool LoadCombine::runOnBasicBlock(BasicBlock &BB) {
-  if (skipOptnoneFunction(BB))
+  if (skipBasicBlock(BB))
     return false;
 
   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
index 856c3ca..786cd72 100644 (file)
@@ -119,7 +119,7 @@ bool LoopDeletion::isLoopDead(Loop *L,
 /// NOTE: This entire process relies pretty heavily on LoopSimplify and LCSSA
 /// in order to make various safety checks work.
 bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
index 87439ec..68bd672 100644 (file)
@@ -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;
index 4d2f4bc..431ac47 100644 (file)
@@ -65,7 +65,7 @@ Pass *llvm::createLoopInstSimplifyPass() {
 }
 
 bool LoopInstSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   DominatorTreeWrapperPass *DTWP =
index 1a51df8..9a7e2c7 100644 (file)
@@ -531,6 +531,9 @@ public:
   }
 
   bool runOnFunction(Function &F) override {
+    if (skipFunction(F))
+      return false;
+
     auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
     auto *LAA = &getAnalysis<LoopAccessAnalysis>();
     auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
index 3fb0a10..825cb09 100644 (file)
@@ -1536,7 +1536,7 @@ bool LoopReroll::reroll(Instruction *IV, Loop *L, BasicBlock *Header,
 }
 
 bool LoopReroll::runOnLoop(Loop *L, LPPassManager &LPM) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
index 1c567fd..ac00828 100644 (file)
@@ -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();
 
index a15d1e8..d908dc7 100644 (file)
@@ -91,7 +91,7 @@ static bool simplifyLoopCFG(Loop *L, DominatorTree *DT, LoopInfo *LI) {
 /// runOnLoop - Perform basic CFG simplifications to assist other loop passes.
 /// For now, this only attempts to merge blocks in the trivial case.
 bool LoopSimplifyCFG::runOnLoop(Loop *L, LPPassManager &) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
index 746adea..b4b6fd1 100644 (file)
@@ -5002,7 +5002,7 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const {
 }
 
 bool LoopStrengthReduce::runOnLoop(Loop *L, LPPassManager & /*LPM*/) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   auto &IU = getAnalysis<IVUsers>();
index 01a8ad8..685ce9e 100644 (file)
@@ -787,7 +787,7 @@ public:
   Optional<bool> ProvidedRuntime;
 
   bool runOnLoop(Loop *L, LPPassManager &) override {
-    if (skipOptnoneFunction(L))
+    if (skipLoop(L))
       return false;
 
     Function &F = *L->getHeader()->getParent();
index 955604f..310f41e 100644 (file)
@@ -420,7 +420,7 @@ static Value *FindLIVLoopCondition(Value *Cond, Loop *L, bool &Changed) {
 }
 
 bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) {
-  if (skipOptnoneFunction(L))
+  if (skipLoop(L))
     return false;
 
   AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
index df0094d..7ccf227 100644 (file)
@@ -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.
index 47d3742..c7e7547 100644 (file)
@@ -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; ) {
index 26359f9..a51204a 100644 (file)
@@ -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;
index cc4ecc7..4a08f89 100644 (file)
@@ -560,6 +560,9 @@ bool MergedLoadStoreMotion::mergeStores(BasicBlock *T) {
 /// \brief Run the transformation for each function
 ///
 bool MergedLoadStoreMotion::runOnFunction(Function &F) {
+  if (skipFunction(F))
+    return false;
+
   auto *MDWP = getAnalysisIfAvailable<MemoryDependenceWrapperPass>();
   MD = MDWP ? &MDWP->getMemDep() : nullptr;
   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
index 208720f..f69c5df 100644 (file)
@@ -208,7 +208,7 @@ FunctionPass *llvm::createNaryReassociatePass() {
 }
 
 bool NaryReassociate::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
index b22e2cd..5e9a0b5 100644 (file)
@@ -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
index 2242a2b..f1f36b7 100644 (file)
@@ -1568,7 +1568,7 @@ FunctionPass *llvm::createSCCPPass() {
 // and return true if the function was modified.
 //
 bool SCCP::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   DEBUG(dbgs() << "SCCP on function '" << F.getName() << "'\n");
@@ -1705,6 +1705,9 @@ static bool AddressIsTaken(const GlobalValue *GV) {
 }
 
 bool IPSCCP::runOnModule(Module &M) {
+  if (skipModule(M))
+    return false;
+
   const DataLayout &DL = M.getDataLayout();
   const TargetLibraryInfo *TLI =
       &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
index 3c42b79..6758879 100644 (file)
@@ -43,6 +43,7 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Operator.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
@@ -4229,6 +4230,9 @@ PreservedAnalyses SROA::runImpl(Function &F, DominatorTree &RunDT,
 }
 
 PreservedAnalyses SROA::run(Function &F, AnalysisManager<Function> &AM) {
+  if (skipPassForFunction(name(), F))
+    return PreservedAnalyses::all();
+
   return runImpl(F, AM.getResult<DominatorTreeAnalysis>(F),
                  AM.getResult<AssumptionAnalysis>(F));
 }
@@ -4246,7 +4250,7 @@ public:
     initializeSROALegacyPassPass(*PassRegistry::getPassRegistry());
   }
   bool runOnFunction(Function &F) override {
-    if (skipOptnoneFunction(F))
+    if (skipFunction(F))
       return false;
 
     auto PA = Impl.runImpl(
index 6633388..5e78269 100644 (file)
@@ -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);
index f94aa9e..2bc0087 100644 (file)
@@ -1064,7 +1064,7 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
 }
 
 bool SeparateConstOffsetFromGEP::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   if (DisableSeparateConstOffsetFromGEP)
index 30fbe04..7835eb6 100644 (file)
@@ -36,6 +36,7 @@
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/OptBisect.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/Utils/Local.h"
@@ -187,6 +188,9 @@ SimplifyCFGPass::SimplifyCFGPass(int BonusInstThreshold)
 
 PreservedAnalyses SimplifyCFGPass::run(Function &F,
                                        AnalysisManager<Function> &AM) {
+  if (skipPassForFunction(name(), F))
+    return PreservedAnalyses::all();
+
   auto &TTI = AM.getResult<TargetIRAnalysis>(F);
   auto &AC = AM.getResult<AssumptionAnalysis>(F);
 
@@ -212,7 +216,7 @@ struct CFGSimplifyPass : public FunctionPass {
     if (PredicateFtor && !PredicateFtor(F))
       return false;
 
-    if (skipOptnoneFunction(F))
+    if (skipFunction(F))
       return false;
 
     AssumptionCache *AC =
index 6b82943..2d49d76 100644 (file)
@@ -141,7 +141,7 @@ void SpeculativeExecution::getAnalysisUsage(AnalysisUsage &AU) const {
 }
 
 bool SpeculativeExecution::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
index 8ee0bbb..03de393 100644 (file)
@@ -682,7 +682,7 @@ void StraightLineStrengthReduce::rewriteCandidateWithBasis(
 }
 
 bool StraightLineStrengthReduce::runOnFunction(Function &F) {
-  if (skipOptnoneFunction(F))
+  if (skipFunction(F))
     return false;
 
   TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
index c809944..132bf82 100644 (file)
@@ -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")
index aa1e35d..8b70cb8 100644 (file)
@@ -59,13 +59,13 @@ INITIALIZE_PASS_END(PromotePass, "mem2reg", "Promote Memory to Register",
                 false, false)
 
 bool PromotePass::runOnFunction(Function &F) {
+  if (skipFunction(F))
+    return false;
+
   std::vector<AllocaInst*> Allocas;
 
   BasicBlock &BB = F.getEntryBlock();  // Get the entry node for the function
 
-  if (F.hasFnAttribute(Attribute::OptimizeNone))
-    return false;
-
   bool Changed  = false;
 
   DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
index b43951d..72ac7a5 100644 (file)
@@ -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() <<
index 90170e7..6c57198 100644 (file)
@@ -1707,6 +1707,9 @@ struct LoopVectorize : public FunctionPass {
   BlockFrequency ColdEntryFreq;
 
   bool runOnFunction(Function &F) override {
+    if (skipFunction(F))
+      return false;
+
     SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
     LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
     TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
index 500919f..f1bfbc2 100644 (file)
@@ -3396,7 +3396,7 @@ struct SLPVectorizer : public FunctionPass {
   }
 
   bool runOnFunction(Function &F) override {
-    if (skipOptnoneFunction(F))
+    if (skipFunction(F))
       return false;
 
     SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
diff --git a/test/Other/opt-bisect-helper.py b/test/Other/opt-bisect-helper.py
new file mode 100755 (executable)
index 0000000..d75950f
--- /dev/null
@@ -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 (file)
index 0000000..8c39187
--- /dev/null
@@ -0,0 +1,148 @@
+; This file verifies the behavior of the OptBisect class, which is used to
+; diagnose optimization related failures.  The tests check various
+; invocations that result in different sets of optimization passes that
+; are run in different ways.
+;
+; This set of tests exercises the legacy pass manager interface to the OptBisect
+; class.  Because the exact set of optimizations that will be run may
+; change over time, these tests are written in a more general manner than the
+; corresponding tests for the new pass manager.
+;
+; Don't use NEXT checks or hard-code pass numbering so that this won't fail if
+; new passes are inserted.
+
+
+; Verify that the file can be compiled to an object file at -O3 with all
+; skippable passes skipped.
+
+; RUN: opt -O3 -opt-bisect-limit=0 < %s | llc -O3 -opt-bisect-limit=0
+
+
+; Verify that no skippable passes are run with -opt-bisect-limit=0.
+
+; RUN: opt -disable-output -disable-verify -O3 -opt-bisect-limit=0 %s 2>&1 \
+; RUN:     | FileCheck %s --check-prefix=CHECK-SKIP-ALL
+; CHECK-SKIP-ALL: BISECT: NOT running pass ({{[0-9]+}})
+; CHECK-SKIP-ALL-NOT: BISECT: running pass ({{[0-9]+}})
+
+
+; Verify that we can use the opt-bisect-helper.py script (derived from
+; utils/bisect) to locate the optimization that inlines the call to
+; f2() in f3().
+
+; RUN: %python %S/opt-bisect-helper.py --start=0 --end=256 --optcmd=opt \
+; RUN:         --filecheckcmd=FileCheck --test=%s \
+; RUN:         --prefix=CHECK-BISECT-INLINE-HELPER \
+; RUN:         | FileCheck %s --check-prefix=CHECK-BISECT-INLINE-RESULT
+; The helper script uses this to find the optimization that inlines the call.
+; CHECK-BISECT-INLINE-HELPER: call i32 @f2()
+; These checks verifies that the optimization was found.
+; CHECK-BISECT-INLINE-RESULT-NOT: Last good count: 0
+; CHECK-BISECT-INLINE-RESULT: Last good count: {{[0-9]+}}
+
+
+; Test a module pass.
+
+; RUN: opt -disable-output -disable-verify -deadargelim -opt-bisect-limit=-1 %s \
+; RUN:     2>&1 | FileCheck %s --check-prefix=CHECK-DEADARG
+; CHECK-DEADARG: BISECT: running pass ({{[0-9]+}}) Dead Argument Elimination on module
+
+; RUN: opt -disable-output -disable-verify -deadargelim -opt-bisect-limit=0 %s \
+; RUN:     2>&1 | FileCheck %s --check-prefix=CHECK-NOT-DEADARG
+; CHECK-NOT-DEADARG: BISECT: NOT running pass ({{[0-9]+}}) Dead Argument Elimination on module
+
+
+; Test an SCC pass.
+
+; RUN: opt -disable-output -disable-verify -inline -opt-bisect-limit=-1 %s \
+; RUN:     2>&1 | FileCheck %s --check-prefix=CHECK-INLINE
+; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>)
+; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (g)
+; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f1)
+; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f2)
+; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f3)
+; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>)
+
+; RUN: opt -disable-output -disable-verify -inline -opt-bisect-limit=0 %s \
+; RUN:     2>&1 | FileCheck %s --check-prefix=CHECK-NOT-INLINE
+; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>)
+; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (g)
+; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f1)
+; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f2)
+; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f3)
+; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>)
+
+
+; Test a function pass.
+
+; RUN: opt -disable-output -disable-verify -early-cse -opt-bisect-limit=-1 \
+; RUN:     %s 2>&1 | FileCheck %s --check-prefix=CHECK-EARLY-CSE
+; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f1)
+; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f2)
+; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f3)
+
+; RUN: opt -disable-output -disable-verify -early-cse -opt-bisect-limit=0 %s \
+; RUN:     2>&1 | FileCheck %s --check-prefix=CHECK-NOT-EARLY-CSE
+; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f1)
+; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f2)
+; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f3)
+
+
+; Test a loop pass.
+
+; RUN: opt -disable-output -disable-verify -loop-reduce -opt-bisect-limit=-1 \
+; RUN:      %s 2>&1 | FileCheck %s --check-prefix=CHECK-LOOP-REDUCE
+; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+
+; RUN: opt -disable-output -disable-verify -loop-reduce -opt-bisect-limit=0 \
+; RUN:     %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-LOOP-REDUCE
+; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop
+
+
+declare i32 @g()
+
+define void @f1() {
+entry:
+  br label %loop.0
+loop.0:
+  br i1 undef, label %loop.0.0, label %loop.1
+loop.0.0:
+  br i1 undef, label %loop.0.0, label %loop.0.1
+loop.0.1:
+  br i1 undef, label %loop.0.1, label %loop.0
+loop.1:
+  br i1 undef, label %loop.1, label %loop.1.bb1
+loop.1.bb1:
+  br i1 undef, label %loop.1, label %loop.1.bb2
+loop.1.bb2:
+  br i1 undef, label %end, label %loop.1.0
+loop.1.0:
+  br i1 undef, label %loop.1.0, label %loop.1
+end:
+  ret void
+}
+
+define i32 @f2() {
+entry:
+  ret i32 0
+}
+
+define i32 @f3() {
+entry:
+  %temp = call i32 @g()
+  %icmp = icmp ugt i32 %temp, 2
+  br i1 %icmp, label %bb.true, label %bb.false
+bb.true:
+  %temp2 = call i32 @f2()
+  ret i32 %temp2
+bb.false:
+  ret i32 0
+}
diff --git a/test/Other/opt-bisect-new-pass-manager.ll b/test/Other/opt-bisect-new-pass-manager.ll
new file mode 100644 (file)
index 0000000..3927422
--- /dev/null
@@ -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
+}