mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-27 05:30:49 +00:00
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:
parent
a7af0d6280
commit
c852398cbc
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
139
include/llvm/IR/OptBisect.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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>();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -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>();
|
||||
|
@ -39,6 +39,7 @@ add_llvm_library(LLVMCore
|
||||
Module.cpp
|
||||
ModuleSummaryIndex.cpp
|
||||
Operator.cpp
|
||||
OptBisect.cpp
|
||||
Pass.cpp
|
||||
PassManager.cpp
|
||||
PassRegistry.cpp
|
||||
|
@ -325,3 +325,7 @@ void LLVMContext::disableDebugTypeODRUniquing() { pImpl->DITypeMap.reset(); }
|
||||
void LLVMContext::setDiscardValueNames(bool Discard) {
|
||||
pImpl->DiscardValueNames = Discard;
|
||||
}
|
||||
|
||||
OptBisect &LLVMContext::getOptBisect() {
|
||||
return pImpl->getOptBisect();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
176
lib/IR/OptBisect.cpp
Normal 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);
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 "..."
|
||||
|
@ -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.
|
||||
|
@ -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("");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -1051,6 +1051,9 @@ bool LowerBitSets::eraseBitSetMetadata() {
|
||||
}
|
||||
|
||||
bool LowerBitSets::runOnModule(Module &M) {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
bool Changed = buildBitSets();
|
||||
Changed |= eraseBitSetMetadata();
|
||||
return Changed;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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>();
|
||||
|
@ -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>();
|
||||
|
@ -58,7 +58,7 @@ namespace {
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
if (skipOptnoneFunction(F))
|
||||
if (skipFunction(F))
|
||||
return false;
|
||||
|
||||
AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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(
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -65,7 +65,7 @@ Pass *llvm::createLoopInstSimplifyPass() {
|
||||
}
|
||||
|
||||
bool LoopInstSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||
if (skipOptnoneFunction(L))
|
||||
if (skipLoop(L))
|
||||
return false;
|
||||
|
||||
DominatorTreeWrapperPass *DTWP =
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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>();
|
||||
|
@ -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();
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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; ) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -1064,7 +1064,7 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
|
||||
}
|
||||
|
||||
bool SeparateConstOffsetFromGEP::runOnFunction(Function &F) {
|
||||
if (skipOptnoneFunction(F))
|
||||
if (skipFunction(F))
|
||||
return false;
|
||||
|
||||
if (DisableSeparateConstOffsetFromGEP)
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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")
|
||||
|
@ -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();
|
||||
|
@ -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() <<
|
||||
|
@ -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);
|
||||
|
@ -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
39
test/Other/opt-bisect-helper.py
Executable 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)
|
148
test/Other/opt-bisect-legacy-pass-manager.ll
Normal file
148
test/Other/opt-bisect-legacy-pass-manager.ll
Normal 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
|
||||
}
|
109
test/Other/opt-bisect-new-pass-manager.ll
Normal file
109
test/Other/opt-bisect-new-pass-manager.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user