[mlir][NFC] Wrap the cl::opts in JitRunner within a struct to avoid global initializers.

Summary: This avoids the need for having global static initializers within the JITRunner support library, and only constructs the options when the runner is invoked.

Differential Revision: https://reviews.llvm.org/D77760
This commit is contained in:
River Riddle 2020-04-08 18:33:24 -07:00
parent 7baad0c53c
commit 293c5210ec
1 changed files with 80 additions and 70 deletions

View File

@ -41,54 +41,58 @@
using namespace mlir;
using llvm::Error;
static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
llvm::cl::desc("<input file>"),
llvm::cl::init("-"));
static llvm::cl::opt<std::string>
mainFuncName("e", llvm::cl::desc("The function to be called"),
llvm::cl::value_desc("<function name>"),
llvm::cl::init("main"));
static llvm::cl::opt<std::string> mainFuncType(
"entry-point-result",
llvm::cl::desc("Textual description of the function type to be called"),
llvm::cl::value_desc("f32 | void"), llvm::cl::init("f32"));
namespace {
/// This options struct prevents the need for global static initializers, and
/// is only initialized if the JITRunner is invoked.
struct Options {
llvm::cl::opt<std::string> inputFilename{llvm::cl::Positional,
llvm::cl::desc("<input file>"),
llvm::cl::init("-")};
llvm::cl::opt<std::string> mainFuncName{
"e", llvm::cl::desc("The function to be called"),
llvm::cl::value_desc("<function name>"), llvm::cl::init("main")};
llvm::cl::opt<std::string> mainFuncType{
"entry-point-result",
llvm::cl::desc("Textual description of the function type to be called"),
llvm::cl::value_desc("f32 | void"), llvm::cl::init("f32")};
static llvm::cl::OptionCategory optFlags("opt-like flags");
llvm::cl::OptionCategory optFlags{"opt-like flags"};
// CLI list of pass information
static llvm::cl::list<const llvm::PassInfo *, bool, llvm::PassNameParser>
llvmPasses(llvm::cl::desc("LLVM optimizing passes to run"),
llvm::cl::cat(optFlags));
// CLI list of pass information
llvm::cl::list<const llvm::PassInfo *, bool, llvm::PassNameParser> llvmPasses{
llvm::cl::desc("LLVM optimizing passes to run"), llvm::cl::cat(optFlags)};
// CLI variables for -On options.
static llvm::cl::opt<bool>
optO0("O0", llvm::cl::desc("Run opt passes and codegen at O0"),
llvm::cl::cat(optFlags));
static llvm::cl::opt<bool>
optO1("O1", llvm::cl::desc("Run opt passes and codegen at O1"),
llvm::cl::cat(optFlags));
static llvm::cl::opt<bool>
optO2("O2", llvm::cl::desc("Run opt passes and codegen at O2"),
llvm::cl::cat(optFlags));
static llvm::cl::opt<bool>
optO3("O3", llvm::cl::desc("Run opt passes and codegen at O3"),
llvm::cl::cat(optFlags));
// CLI variables for -On options.
llvm::cl::opt<bool> optO0{"O0",
llvm::cl::desc("Run opt passes and codegen at O0"),
llvm::cl::cat(optFlags)};
llvm::cl::opt<bool> optO1{"O1",
llvm::cl::desc("Run opt passes and codegen at O1"),
llvm::cl::cat(optFlags)};
llvm::cl::opt<bool> optO2{"O2",
llvm::cl::desc("Run opt passes and codegen at O2"),
llvm::cl::cat(optFlags)};
llvm::cl::opt<bool> optO3{"O3",
llvm::cl::desc("Run opt passes and codegen at O3"),
llvm::cl::cat(optFlags)};
static llvm::cl::OptionCategory clOptionsCategory("linking options");
static llvm::cl::list<std::string>
clSharedLibs("shared-libs", llvm::cl::desc("Libraries to link dynamically"),
llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated,
llvm::cl::cat(clOptionsCategory));
llvm::cl::OptionCategory clOptionsCategory{"linking options"};
llvm::cl::list<std::string> clSharedLibs{
"shared-libs", llvm::cl::desc("Libraries to link dynamically"),
llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated,
llvm::cl::cat(clOptionsCategory)};
// CLI variables for debugging.
static llvm::cl::opt<bool> dumpObjectFile(
"dump-object-file",
llvm::cl::desc("Dump JITted-compiled object to file specified with "
"-object-filename (<input file>.o by default)."));
/// CLI variables for debugging.
llvm::cl::opt<bool> dumpObjectFile{
"dump-object-file",
llvm::cl::desc("Dump JITted-compiled object to file specified with "
"-object-filename (<input file>.o by default).")};
static llvm::cl::opt<std::string> objectFilename(
"object-filename",
llvm::cl::desc("Dump JITted-compiled object to file <input file>.o"));
llvm::cl::opt<std::string> objectFilename{
"object-filename",
llvm::cl::desc("Dump JITted-compiled object to file <input file>.o")};
};
} // end anonymous namespace
static OwningModuleRef parseMLIRInput(StringRef inputFilename,
MLIRContext *context) {
@ -110,10 +114,10 @@ static inline Error make_string_error(const Twine &message) {
llvm::inconvertibleErrorCode());
}
static Optional<unsigned> getCommandLineOptLevel() {
static Optional<unsigned> getCommandLineOptLevel(Options &options) {
Optional<unsigned> optLevel;
SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
optO0, optO1, optO2, optO3};
options.optO0, options.optO1, options.optO2, options.optO3};
// Determine if there is an optimization flag present.
for (unsigned j = 0; j < 4; ++j) {
@ -128,14 +132,15 @@ static Optional<unsigned> getCommandLineOptLevel() {
// JIT-compile the given module and run "entryPoint" with "args" as arguments.
static Error
compileAndExecute(ModuleOp module, StringRef entryPoint,
compileAndExecute(Options &options, ModuleOp module, StringRef entryPoint,
std::function<llvm::Error(llvm::Module *)> transformer,
void **args) {
Optional<llvm::CodeGenOpt::Level> jitCodeGenOptLevel;
if (auto clOptLevel = getCommandLineOptLevel())
if (auto clOptLevel = getCommandLineOptLevel(options))
jitCodeGenOptLevel =
static_cast<llvm::CodeGenOpt::Level>(clOptLevel.getValue());
SmallVector<StringRef, 4> libs(clSharedLibs.begin(), clSharedLibs.end());
SmallVector<StringRef, 4> libs(options.clSharedLibs.begin(),
options.clSharedLibs.end());
auto expectedEngine = mlir::ExecutionEngine::create(module, transformer,
jitCodeGenOptLevel, libs);
if (!expectedEngine)
@ -146,9 +151,10 @@ compileAndExecute(ModuleOp module, StringRef entryPoint,
if (!expectedFPtr)
return expectedFPtr.takeError();
if (dumpObjectFile)
engine->dumpToObjectFile(objectFilename.empty() ? inputFilename + ".o"
: objectFilename);
if (options.dumpObjectFile)
engine->dumpToObjectFile(options.objectFilename.empty()
? options.inputFilename + ".o"
: options.objectFilename);
void (*fptr)(void **) = *expectedFPtr;
(*fptr)(args);
@ -157,17 +163,17 @@ compileAndExecute(ModuleOp module, StringRef entryPoint,
}
static Error compileAndExecuteVoidFunction(
ModuleOp module, StringRef entryPoint,
Options &options, ModuleOp module, StringRef entryPoint,
std::function<llvm::Error(llvm::Module *)> transformer) {
auto mainFunction = module.lookupSymbol<LLVM::LLVMFuncOp>(entryPoint);
if (!mainFunction || mainFunction.getBlocks().empty())
return make_string_error("entry point not found");
void *empty = nullptr;
return compileAndExecute(module, entryPoint, transformer, &empty);
return compileAndExecute(options, module, entryPoint, transformer, &empty);
}
static Error compileAndExecuteSingleFloatReturnFunction(
ModuleOp module, StringRef entryPoint,
Options &options, ModuleOp module, StringRef entryPoint,
std::function<llvm::Error(llvm::Module *)> transformer) {
auto mainFunction = module.lookupSymbol<LLVM::LLVMFuncOp>(entryPoint);
if (!mainFunction || mainFunction.isExternal())
@ -184,28 +190,30 @@ static Error compileAndExecuteSingleFloatReturnFunction(
void *data;
} data;
data.data = &res;
if (auto error =
compileAndExecute(module, entryPoint, transformer, (void **)&data))
if (auto error = compileAndExecute(options, module, entryPoint, transformer,
(void **)&data))
return error;
// Intentional printing of the output so we can test.
llvm::outs() << res << '\n';
return Error::success();
}
// Entry point for all CPU runners. Expects the common argc/argv arguments for
// standard C++ main functions and an mlirTransformer.
// The latter is applied after parsing the input into MLIR IR and before passing
// the MLIR module to the ExecutionEngine.
/// Entry point for all CPU runners. Expects the common argc/argv arguments for
/// standard C++ main functions and an mlirTransformer.
/// The latter is applied after parsing the input into MLIR IR and before
/// passing the MLIR module to the ExecutionEngine.
int mlir::JitRunnerMain(
int argc, char **argv,
function_ref<LogicalResult(mlir::ModuleOp)> mlirTransformer) {
// Create the options struct containing the command line options for the
// runner. This must come before the command line options are parsed.
Options options;
llvm::cl::ParseCommandLineOptions(argc, argv, "MLIR CPU execution driver\n");
Optional<unsigned> optLevel = getCommandLineOptLevel();
Optional<unsigned> optLevel = getCommandLineOptLevel(options);
SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
optO0, optO1, optO2, optO3};
options.optO0, options.optO1, options.optO2, options.optO3};
unsigned optCLIPosition = 0;
// Determine if there is an optimization flag present, and its CLI position
// (optCLIPosition).
@ -220,16 +228,16 @@ int mlir::JitRunnerMain(
// insert any optimization passes in that vector (optPosition).
SmallVector<const llvm::PassInfo *, 4> passes;
unsigned optPosition = 0;
for (unsigned i = 0, e = llvmPasses.size(); i < e; ++i) {
passes.push_back(llvmPasses[i]);
if (optCLIPosition < llvmPasses.getPosition(i)) {
for (unsigned i = 0, e = options.llvmPasses.size(); i < e; ++i) {
passes.push_back(options.llvmPasses[i]);
if (optCLIPosition < options.llvmPasses.getPosition(i)) {
optPosition = i;
optCLIPosition = UINT_MAX; // To ensure we never insert again
}
}
MLIRContext context;
auto m = parseMLIRInput(inputFilename, &context);
auto m = parseMLIRInput(options.inputFilename, &context);
if (!m) {
llvm::errs() << "could not parse the input IR\n";
return 1;
@ -254,17 +262,19 @@ int mlir::JitRunnerMain(
passes, optLevel, /*targetMachine=*/tmOrError->get(), optPosition);
// Get the function used to compile and execute the module.
using CompileAndExecuteFnT = Error (*)(
ModuleOp, StringRef, std::function<llvm::Error(llvm::Module *)>);
using CompileAndExecuteFnT =
Error (*)(Options &, ModuleOp, StringRef,
std::function<llvm::Error(llvm::Module *)>);
auto compileAndExecuteFn =
llvm::StringSwitch<CompileAndExecuteFnT>(mainFuncType.getValue())
llvm::StringSwitch<CompileAndExecuteFnT>(options.mainFuncType.getValue())
.Case("f32", compileAndExecuteSingleFloatReturnFunction)
.Case("void", compileAndExecuteVoidFunction)
.Default(nullptr);
Error error =
compileAndExecuteFn
? compileAndExecuteFn(m.get(), mainFuncName.getValue(), transformer)
? compileAndExecuteFn(options, m.get(),
options.mainFuncName.getValue(), transformer)
: make_string_error("unsupported function type");
int exitCode = EXIT_SUCCESS;