diff options
-rw-r--r-- | test/Other/pass-pipeline-parsing.ll | 2 | ||||
-rw-r--r-- | tools/opt/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tools/opt/NewPMDriver.cpp | 46 | ||||
-rw-r--r-- | tools/opt/NewPMDriver.h | 42 | ||||
-rw-r--r-- | tools/opt/Passes.cpp | 93 | ||||
-rw-r--r-- | tools/opt/Passes.h | 56 | ||||
-rw-r--r-- | tools/opt/opt.cpp | 21 |
7 files changed, 261 insertions, 1 deletions
diff --git a/test/Other/pass-pipeline-parsing.ll b/test/Other/pass-pipeline-parsing.ll new file mode 100644 index 0000000000..c490f56ba8 --- /dev/null +++ b/test/Other/pass-pipeline-parsing.ll @@ -0,0 +1,2 @@ +; RUN: opt -disable-output -passes=no-op-module,no-op-module %s +; RUN: opt -disable-output -passes='module(no-op-module,no-op-module)' %s diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index f96f9b35ef..c007e0fa2e 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -23,6 +23,8 @@ set(LLVM_NO_DEAD_STRIP 1) add_llvm_tool(opt AnalysisWrappers.cpp GraphPrinters.cpp + NewPMDriver.cpp + Passes.cpp PrintSCC.cpp opt.cpp ) diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp new file mode 100644 index 0000000000..e577995e26 --- /dev/null +++ b/tools/opt/NewPMDriver.cpp @@ -0,0 +1,46 @@ +//===- NewPMDriver.cpp - Driver for opt with new PM -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file is just a split of the code that logically belongs in opt.cpp but +/// that includes the new pass manager headers. +/// +//===----------------------------------------------------------------------===// + +#include "NewPMDriver.h" +#include "Passes.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ToolOutputFile.h" + +using namespace llvm; + +bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, + tool_output_file *Out, StringRef PassPipeline, + bool NoOutput) { + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + + ModulePassManager MPM; + if (!parsePassPipeline(MPM, PassPipeline)) { + errs() << Arg0 << ": unable to parse pass pipeline description.\n"; + return false; + } + + // Now that we have all of the passes ready, run them. + MPM.run(&M); + + // Declare success. + if (!NoOutput) + Out->keep(); + return true; +} diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h new file mode 100644 index 0000000000..17ac75be54 --- /dev/null +++ b/tools/opt/NewPMDriver.h @@ -0,0 +1,42 @@ +//===- NewPMDriver.h - Function to drive opt with the new PM ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// A single function which is called to drive the opt behavior for the new +/// PassManager. +/// +/// This is only in a separate TU with a header to avoid including all of the +/// old pass manager headers and the new pass manager headers into the same +/// file. Eventually all of the routines here will get folded back into +/// opt.cpp. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OPT_NEW_PM_DRIVER_H +#define LLVM_TOOLS_OPT_NEW_PM_DRIVER_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class LLVMContext; +class Module; +class tool_output_file; + +/// \brief Driver function to run the new pass manager over a module. +/// +/// This function only exists factored away from opt.cpp in order to prevent +/// inclusion of the new pass manager headers and the old headers into the same +/// file. It's interface is consequentially somewhat ad-hoc, but will go away +/// when the transition finishes. +bool runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, + tool_output_file *Out, StringRef PassPipeline, + bool NoOutput); +} + +#endif diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp new file mode 100644 index 0000000000..49751269df --- /dev/null +++ b/tools/opt/Passes.cpp @@ -0,0 +1,93 @@ +//===- Passes.cpp - Parsing, selection, and running of passes -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file provides the infrastructure to parse and build a custom pass +/// manager based on a commandline flag. It also provides helpers to aid in +/// analyzing, debugging, and testing pass structures. +/// +//===----------------------------------------------------------------------===// + +#include "Passes.h" +#include "llvm/IR/PassManager.h" + +using namespace llvm; + +namespace { + + /// \brief No-op module pass which does nothing. +struct NoOpModulePass { + PreservedAnalyses run(Module *M) { return PreservedAnalyses::all(); } +}; + +} // End anonymous namespace. + +// FIXME: Factor all of the parsing logic into a .def file that we include +// under different macros. +static bool isModulePassName(StringRef Name) { + if (Name == "no-op-module") return true; + + return false; +} + +static bool parseModulePassName(ModulePassManager &MPM, StringRef Name) { + assert(isModulePassName(Name)); + if (Name == "no-op-module") { + MPM.addPass(NoOpModulePass()); + return true; + } + return false; +} + +static bool parseModulePassPipeline(ModulePassManager &MPM, + StringRef &PipelineText) { + for (;;) { + // Parse nested pass managers by recursing. + if (PipelineText.startswith("module(")) { + PipelineText = PipelineText.substr(strlen("module(")); + if (!parseModulePassPipeline(MPM, PipelineText)) + return false; + assert(!PipelineText.empty() && PipelineText[0] == ')'); + PipelineText = PipelineText.substr(1); + } else { + // Otherwise try to parse a pass name. + size_t End = PipelineText.find_first_of(",)"); + if (!parseModulePassName(MPM, PipelineText.substr(0, End))) + return false; + + PipelineText = PipelineText.substr(End); + } + + if (PipelineText.empty() || PipelineText[0] == ')') + return true; + + assert(PipelineText[0] == ','); + PipelineText = PipelineText.substr(1); + } +} + +// Primary pass pipeline description parsing routine. +// FIXME: Should this routine accept a TargetMachine or require the caller to +// pre-populate the analysis managers with target-specific stuff? +bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText) { + // Look at the first entry to figure out which layer to start parsing at. + if (PipelineText.startswith("module(")) + return parseModulePassPipeline(MPM, PipelineText); + + // FIXME: Support parsing function pass manager nests. + + // This isn't a direct pass manager name, look for the end of a pass name. + StringRef FirstName = PipelineText.substr(0, PipelineText.find_first_of(",")); + if (isModulePassName(FirstName)) + return parseModulePassPipeline(MPM, PipelineText); + + // FIXME: Support parsing function pass names. + + return false; +} diff --git a/tools/opt/Passes.h b/tools/opt/Passes.h new file mode 100644 index 0000000000..6016b74c80 --- /dev/null +++ b/tools/opt/Passes.h @@ -0,0 +1,56 @@ +//===- Passes.h - Parsing, selection, and running of passes -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// Interfaces for producing common pass manager configurations and parsing +/// textual pass specifications. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OPT_PASSES_H +#define LLVM_TOOLS_OPT_PASSES_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class ModulePassManager; + +/// \brief Parse a textual pass pipeline description into a \c ModulePassManager. +/// +/// The format of the textual pass pipeline description looks something like: +/// +/// module(function(instcombine,sroa),dce,cgscc(inliner,function(...)),...) +/// +/// Pass managers have ()s describing the nest structure of passes. All passes +/// are comma separated. As a special shortcut, if the very first pass is not +/// a module pass (as a module pass manager is), this will automatically form +/// the shortest stack of pass managers that allow inserting that first pass. +/// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and loop passes +/// 'lpassN', all of these are valid: +/// +/// fpass1,fpass2,fpass3 +/// cgpass1,cgpass2,cgpass3 +/// lpass1,lpass2,lpass3 +/// +/// And they are equivalent to the following (resp.): +/// +/// module(function(fpass1,fpass2,fpass3)) +/// module(cgscc(cgpass1,cgpass2,cgpass3)) +/// module(function(loop(lpass1,lpass2,lpass3))) +/// +/// This shortcut is especially useful for debugging and testing small pass +/// combinations. Note that these shortcuts don't introduce any other magic. If +/// the sequence of passes aren't all the exact same kind of pass, it will be +/// an error. You cannot mix different levels implicitly, you must explicitly +/// form a pass manager in which to nest passes. +bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText); + +} + +#endif diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 9e76451229..5138ef68c0 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" +#include "NewPMDriver.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/CallGraph.h" @@ -24,6 +24,7 @@ #include "llvm/CodeGen/CommandFlags.h" #include "llvm/DebugInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/PrintModulePass.h" #include "llvm/IRReader/IRReader.h" @@ -55,6 +56,15 @@ using namespace llvm; static cl::list<const PassInfo*, bool, PassNameParser> PassList(cl::desc("Optimizations available:")); +// This flag specifies a textual description of the optimization pass pipeline +// to run over the module. This flag switches opt to use the new pass manager +// infrastructure, completely disabling all of the flags specific to the old +// pass management. +static cl::opt<std::string> PassPipeline( + "passes", + cl::desc("A textual description of the pass pipeline for optimizing"), + cl::Hidden); + // Other command line options... // static cl::opt<std::string> @@ -660,6 +670,15 @@ int main(int argc, char **argv) { if (CheckBitcodeOutputToConsole(Out->os(), !Quiet)) NoOutput = true; + if (PassPipeline.getNumOccurrences() > 0) + // The user has asked to use the new pass manager and provided a pipeline + // string. Hand off the rest of the functionality to the new code for that + // layer. + return runPassPipeline(argv[0], Context, *M.get(), Out.get(), PassPipeline, + NoOutput) + ? 0 + : 1; + // Create a PassManager to hold and optimize the collection of passes we are // about to build. // |