Initial implementation of optimization bisect support.

This patch implements a optimization bisect feature, which will allow optimizations to be selectively disabled at compile time in order to track down test failures that are caused by incorrect optimizations.

The bisection is enabled using a new command line option (-opt-bisect-limit).  Individual passes that may be skipped call the OptBisect object (via an LLVMContext) to see if they should be skipped based on the bisect limit.  A finer level of control (disabling individual transformations) can be managed through an addition OptBisect method, but this is not yet used.

The skip checking in this implementation is based on (and replaces) the skipOptnoneFunction check.  Where that check was being called, a new call has been inserted in its place which checks the bisect limit and the optnone attribute.  A new function call has been added for module and SCC passes that behaves in a similar way.

Differential Revision: http://reviews.llvm.org/D19172



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267022 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Kaylor 2016-04-21 17:58:54 +00:00
parent a7af0d6280
commit c852398cbc
98 changed files with 909 additions and 79 deletions

View 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

View 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

View 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 {

View 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;

139
include/llvm/IR/OptBisect.h Normal file
View File

@ -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

View 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

View 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);
}

View 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");

View 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>();

View 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();

View 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;

View 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;

View 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>();

View 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();

View 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;

View 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;

View 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()) {

View 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");

View 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();

View 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");

View 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();

View 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"

View 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>();

View File

@ -39,6 +39,7 @@ add_llvm_library(LLVMCore
Module.cpp
ModuleSummaryIndex.cpp
Operator.cpp
OptBisect.cpp
Pass.cpp
PassManager.cpp
PassRegistry.cpp

View 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();
}

View 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;
}

View 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();
};
}

176
lib/IR/OptBisect.cpp Normal file
View File

@ -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);
}

View 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()

View 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.

View 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;

View 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();

View 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 "..."

View 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.

View 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("");

View 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

View 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");

View 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.

View 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();

View 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;

View 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);
}

View 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();

View 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;

View 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];

View 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;

View 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

View 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)

View 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;

View 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);
}
};

View 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();

View 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

View 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.

View 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.

View 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

View 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);
}

View 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();

View 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");

View 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>();

View 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>();

View File

@ -58,7 +58,7 @@ namespace {
}
bool runOnFunction(Function &F) override {
if (skipOptnoneFunction(F))
if (skipFunction(F))
return false;
AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();

View 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();

View 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");

View 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(

View 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:

View 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");

View 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;

View 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();

View 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();

View 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;

View 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 =

View 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();

View 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();

View 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();

View 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();

View 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>();

View 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();

View 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(

View 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.

View 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; ) {

View 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;

View 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();

View 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);

View 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

View 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();

View 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(

View 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);

View 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)

View 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 =

View 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);

View 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);

View 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")

View 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();

View 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() <<

View 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);

View 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();

39
test/Other/opt-bisect-helper.py Executable file
View File

@ -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)

View File

@ -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
}

View File

@ -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
}