summaryrefslogtreecommitdiffstats
path: root/llvm/lib/IR
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR')
-rw-r--r--llvm/lib/IR/CMakeLists.txt1
-rw-r--r--llvm/lib/IR/LLVMContext.cpp4
-rw-r--r--llvm/lib/IR/LLVMContextImpl.cpp18
-rw-r--r--llvm/lib/IR/LLVMContextImpl.h4
-rw-r--r--llvm/lib/IR/OptBisect.cpp135
-rw-r--r--llvm/lib/IR/Pass.cpp23
6 files changed, 180 insertions, 5 deletions
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index 554ea1422a1..f3f87338ca4 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -39,6 +39,7 @@ add_llvm_library(LLVMCore
Module.cpp
ModuleSummaryIndex.cpp
Operator.cpp
+ OptBisect.cpp
Pass.cpp
PassManager.cpp
PassRegistry.cpp
diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index 45c28061b0c..ee95c4f80e4 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -325,3 +325,7 @@ void LLVMContext::disableDebugTypeODRUniquing() { pImpl->DITypeMap.reset(); }
void LLVMContext::setDiscardValueNames(bool Discard) {
pImpl->DiscardValueNames = Discard;
}
+
+OptBisect &LLVMContext::getOptBisect() {
+ return pImpl->getOptBisect();
+}
diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp
index d5d9038d1e9..d27fcb1f2e7 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -16,6 +16,8 @@
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/OptBisect.h"
+#include "llvm/Support/ManagedStatic.h"
#include <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;
+}
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 0d6d9799b46..a4d7b7eaf9e 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1133,6 +1133,10 @@ public:
/// Destroy the ConstantArrays if they are not used.
void dropTriviallyDeadConstantArrays();
+
+ /// \brief Access the object which manages optimization bisection for failure
+ /// analysis.
+ OptBisect &getOptBisect();
};
}
diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp
new file mode 100644
index 00000000000..74eb9e19e9d
--- /dev/null
+++ b/llvm/lib/IR/OptBisect.cpp
@@ -0,0 +1,135 @@
+//===------- 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 <class UnitT>
+bool OptBisect::shouldRunPass(const Pass *P, const UnitT &U) {
+ if (!BisectEnabled)
+ return true;
+ return checkPass(P->getPassName(), 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;
+}
+
diff --git a/llvm/lib/IR/Pass.cpp b/llvm/lib/IR/Pass.cpp
index 8ce65596b76..69299fea763 100644
--- a/llvm/lib/IR/Pass.cpp
+++ b/llvm/lib/IR/Pass.cpp
@@ -17,6 +17,8 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassNameParser.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/OptBisect.h"
#include "llvm/PassRegistry.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -45,6 +47,10 @@ PassManagerType ModulePass::getPotentialPassManagerType() const {
return PMT_ModulePassManager;
}
+bool ModulePass::skipModule(Module &M) const {
+ return !M.getContext().getOptBisect().shouldRunPass(this, M);
+}
+
bool Pass::mustPreserveAnalysisID(char &AID) const {
return Resolver->getAnalysisIfAvailable(&AID, true) != nullptr;
}
@@ -140,10 +146,13 @@ PassManagerType FunctionPass::getPotentialPassManagerType() const {
return PMT_FunctionPassManager;
}
-bool FunctionPass::skipOptnoneFunction(const Function &F) const {
+bool FunctionPass::skipFunction(const Function &F) const {
+ if (!F.getContext().getOptBisect().shouldRunPass(this, F))
+ return true;
+
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
- DEBUG(dbgs() << "Skipping pass '" << getPassName()
- << "' on function " << F.getName() << "\n");
+ DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function "
+ << F.getName() << "\n");
return true;
}
return false;
@@ -168,9 +177,13 @@ bool BasicBlockPass::doFinalization(Function &) {
return false;
}
-bool BasicBlockPass::skipOptnoneFunction(const BasicBlock &BB) const {
+bool BasicBlockPass::skipBasicBlock(const BasicBlock &BB) const {
const Function *F = BB.getParent();
- if (F && F->hasFnAttribute(Attribute::OptimizeNone)) {
+ if (!F)
+ return false;
+ if (!F->getContext().getOptBisect().shouldRunPass(this, BB))
+ return true;
+ if (F->hasFnAttribute(Attribute::OptimizeNone)) {
// Report this only once per function.
if (&BB == &F->getEntryBlock())
DEBUG(dbgs() << "Skipping pass '" << getPassName()
OpenPOWER on IntegriCloud