1ec44e089SStephen Neuendorffer //===- jit-runner.cpp - MLIR CPU Execution Driver Library -----------------===//
2ec44e089SStephen Neuendorffer //
3ec44e089SStephen Neuendorffer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ec44e089SStephen Neuendorffer // See https://llvm.org/LICENSE.txt for license information.
5ec44e089SStephen Neuendorffer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ec44e089SStephen Neuendorffer //
7ec44e089SStephen Neuendorffer //===----------------------------------------------------------------------===//
8ec44e089SStephen Neuendorffer //
9ec44e089SStephen Neuendorffer // This is a library that provides a shared implementation for command line
10ec44e089SStephen Neuendorffer // utilities that execute an MLIR file on the CPU by translating MLIR to LLVM
11ec44e089SStephen Neuendorffer // IR before JIT-compiling and executing the latter.
12ec44e089SStephen Neuendorffer //
13ec44e089SStephen Neuendorffer // The translation can be customized by providing an MLIR to MLIR
14ec44e089SStephen Neuendorffer // transformation.
15ec44e089SStephen Neuendorffer //===----------------------------------------------------------------------===//
16ec44e089SStephen Neuendorffer
17ec44e089SStephen Neuendorffer #include "mlir/ExecutionEngine/JitRunner.h"
18ec44e089SStephen Neuendorffer
19ec44e089SStephen Neuendorffer #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
20ec44e089SStephen Neuendorffer #include "mlir/ExecutionEngine/ExecutionEngine.h"
21ec44e089SStephen Neuendorffer #include "mlir/ExecutionEngine/OptUtils.h"
2209f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
23ec44e089SStephen Neuendorffer #include "mlir/IR/MLIRContext.h"
249eaff423SRiver Riddle #include "mlir/Parser/Parser.h"
25ec44e089SStephen Neuendorffer #include "mlir/Support/FileUtilities.h"
26ec44e089SStephen Neuendorffer
27ec44e089SStephen Neuendorffer #include "llvm/ADT/STLExtras.h"
28ec44e089SStephen Neuendorffer #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
29*b630bafbSRainer Orth #include "llvm/ExecutionEngine/Orc/LLJIT.h"
30ec44e089SStephen Neuendorffer #include "llvm/IR/IRBuilder.h"
31ec44e089SStephen Neuendorffer #include "llvm/IR/LLVMContext.h"
32ec44e089SStephen Neuendorffer #include "llvm/IR/LegacyPassNameParser.h"
33ec44e089SStephen Neuendorffer #include "llvm/Support/CommandLine.h"
34ec44e089SStephen Neuendorffer #include "llvm/Support/FileUtilities.h"
35ec44e089SStephen Neuendorffer #include "llvm/Support/SourceMgr.h"
36ec44e089SStephen Neuendorffer #include "llvm/Support/StringSaver.h"
37ec44e089SStephen Neuendorffer #include "llvm/Support/ToolOutputFile.h"
38d3ead060SStephen Neuendorffer #include <cstdint>
39ec44e089SStephen Neuendorffer #include <numeric>
404e01184aSMehdi Amini #include <utility>
41ec44e089SStephen Neuendorffer
42ec44e089SStephen Neuendorffer using namespace mlir;
43ec44e089SStephen Neuendorffer using llvm::Error;
44ec44e089SStephen Neuendorffer
45ec44e089SStephen Neuendorffer namespace {
46ec44e089SStephen Neuendorffer /// This options struct prevents the need for global static initializers, and
47ec44e089SStephen Neuendorffer /// is only initialized if the JITRunner is invoked.
48ec44e089SStephen Neuendorffer struct Options {
49ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> inputFilename{llvm::cl::Positional,
50ec44e089SStephen Neuendorffer llvm::cl::desc("<input file>"),
51ec44e089SStephen Neuendorffer llvm::cl::init("-")};
52ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> mainFuncName{
53ec44e089SStephen Neuendorffer "e", llvm::cl::desc("The function to be called"),
54ec44e089SStephen Neuendorffer llvm::cl::value_desc("<function name>"), llvm::cl::init("main")};
55ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> mainFuncType{
56ec44e089SStephen Neuendorffer "entry-point-result",
57ec44e089SStephen Neuendorffer llvm::cl::desc("Textual description of the function type to be called"),
58d3ead060SStephen Neuendorffer llvm::cl::value_desc("f32 | i32 | i64 | void"), llvm::cl::init("f32")};
59ec44e089SStephen Neuendorffer
60ec44e089SStephen Neuendorffer llvm::cl::OptionCategory optFlags{"opt-like flags"};
61ec44e089SStephen Neuendorffer
62ec44e089SStephen Neuendorffer // CLI variables for -On options.
63ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO0{"O0",
64ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O0"),
65ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
66ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO1{"O1",
67ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O1"),
68ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
69ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO2{"O2",
70ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O2"),
71ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
72ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO3{"O3",
73ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O3"),
74ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
75ec44e089SStephen Neuendorffer
76ec44e089SStephen Neuendorffer llvm::cl::OptionCategory clOptionsCategory{"linking options"};
77ec44e089SStephen Neuendorffer llvm::cl::list<std::string> clSharedLibs{
78ec44e089SStephen Neuendorffer "shared-libs", llvm::cl::desc("Libraries to link dynamically"),
79d86a206fSFangrui Song llvm::cl::MiscFlags::CommaSeparated, llvm::cl::cat(clOptionsCategory)};
80ec44e089SStephen Neuendorffer
81ec44e089SStephen Neuendorffer /// CLI variables for debugging.
82ec44e089SStephen Neuendorffer llvm::cl::opt<bool> dumpObjectFile{
83ec44e089SStephen Neuendorffer "dump-object-file",
84ec44e089SStephen Neuendorffer llvm::cl::desc("Dump JITted-compiled object to file specified with "
85ec44e089SStephen Neuendorffer "-object-filename (<input file>.o by default).")};
86ec44e089SStephen Neuendorffer
87ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> objectFilename{
88ec44e089SStephen Neuendorffer "object-filename",
89ec44e089SStephen Neuendorffer llvm::cl::desc("Dump JITted-compiled object to file <input file>.o")};
90*b630bafbSRainer Orth
91*b630bafbSRainer Orth llvm::cl::opt<bool> hostSupportsJit{"host-supports-jit",
92*b630bafbSRainer Orth llvm::cl::desc("Report host JIT support"),
93*b630bafbSRainer Orth llvm::cl::Hidden};
94ec44e089SStephen Neuendorffer };
95f6c9f6ecSEugene Zhulenev
96f6c9f6ecSEugene Zhulenev struct CompileAndExecuteConfig {
97f6c9f6ecSEugene Zhulenev /// LLVM module transformer that is passed to ExecutionEngine.
9807db69efSMehdi Amini std::function<llvm::Error(llvm::Module *)> transformer;
99f6c9f6ecSEugene Zhulenev
100f6c9f6ecSEugene Zhulenev /// A custom function that is passed to ExecutionEngine. It processes MLIR
101f6c9f6ecSEugene Zhulenev /// module and creates LLVM IR module.
102f6c9f6ecSEugene Zhulenev llvm::function_ref<std::unique_ptr<llvm::Module>(ModuleOp,
103f6c9f6ecSEugene Zhulenev llvm::LLVMContext &)>
104f6c9f6ecSEugene Zhulenev llvmModuleBuilder;
105f6c9f6ecSEugene Zhulenev
106f6c9f6ecSEugene Zhulenev /// A custom function that is passed to ExecutinEngine to register symbols at
107f6c9f6ecSEugene Zhulenev /// runtime.
108f6c9f6ecSEugene Zhulenev llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
109f6c9f6ecSEugene Zhulenev runtimeSymbolMap;
110f6c9f6ecSEugene Zhulenev };
111f6c9f6ecSEugene Zhulenev
112be0a7e9fSMehdi Amini } // namespace
113ec44e089SStephen Neuendorffer
parseMLIRInput(StringRef inputFilename,MLIRContext * context)1148f66ab1cSSanjoy Das static OwningOpRef<ModuleOp> parseMLIRInput(StringRef inputFilename,
115ec44e089SStephen Neuendorffer MLIRContext *context) {
116ec44e089SStephen Neuendorffer // Set up the input file.
117ec44e089SStephen Neuendorffer std::string errorMessage;
118ec44e089SStephen Neuendorffer auto file = openInputFile(inputFilename, &errorMessage);
119ec44e089SStephen Neuendorffer if (!file) {
120ec44e089SStephen Neuendorffer llvm::errs() << errorMessage << "\n";
121ec44e089SStephen Neuendorffer return nullptr;
122ec44e089SStephen Neuendorffer }
123ec44e089SStephen Neuendorffer
124ec44e089SStephen Neuendorffer llvm::SourceMgr sourceMgr;
1256842ec42SRiver Riddle sourceMgr.AddNewSourceBuffer(std::move(file), SMLoc());
1260dc66b76SChristian Sigg return parseSourceFile<ModuleOp>(sourceMgr, context);
127ec44e089SStephen Neuendorffer }
128ec44e089SStephen Neuendorffer
makeStringError(const Twine & message)12902b6fb21SMehdi Amini static inline Error makeStringError(const Twine &message) {
130ec44e089SStephen Neuendorffer return llvm::make_error<llvm::StringError>(message.str(),
131ec44e089SStephen Neuendorffer llvm::inconvertibleErrorCode());
132ec44e089SStephen Neuendorffer }
133ec44e089SStephen Neuendorffer
getCommandLineOptLevel(Options & options)134ec44e089SStephen Neuendorffer static Optional<unsigned> getCommandLineOptLevel(Options &options) {
135ec44e089SStephen Neuendorffer Optional<unsigned> optLevel;
136ec44e089SStephen Neuendorffer SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
137ec44e089SStephen Neuendorffer options.optO0, options.optO1, options.optO2, options.optO3};
138ec44e089SStephen Neuendorffer
139ec44e089SStephen Neuendorffer // Determine if there is an optimization flag present.
140ec44e089SStephen Neuendorffer for (unsigned j = 0; j < 4; ++j) {
141ec44e089SStephen Neuendorffer auto &flag = optFlags[j].get();
142ec44e089SStephen Neuendorffer if (flag) {
143ec44e089SStephen Neuendorffer optLevel = j;
144ec44e089SStephen Neuendorffer break;
145ec44e089SStephen Neuendorffer }
146ec44e089SStephen Neuendorffer }
147ec44e089SStephen Neuendorffer return optLevel;
148ec44e089SStephen Neuendorffer }
149ec44e089SStephen Neuendorffer
150ec44e089SStephen Neuendorffer // JIT-compile the given module and run "entryPoint" with "args" as arguments.
compileAndExecute(Options & options,ModuleOp module,StringRef entryPoint,CompileAndExecuteConfig config,void ** args)151f6c9f6ecSEugene Zhulenev static Error compileAndExecute(Options &options, ModuleOp module,
152f6c9f6ecSEugene Zhulenev StringRef entryPoint,
153f6c9f6ecSEugene Zhulenev CompileAndExecuteConfig config, void **args) {
154ec44e089SStephen Neuendorffer Optional<llvm::CodeGenOpt::Level> jitCodeGenOptLevel;
155ec44e089SStephen Neuendorffer if (auto clOptLevel = getCommandLineOptLevel(options))
1566d5fc1e3SKazu Hirata jitCodeGenOptLevel = static_cast<llvm::CodeGenOpt::Level>(*clOptLevel);
1571fc98642SEugene Zhulenev
1581fc98642SEugene Zhulenev // If shared library implements custom mlir-runner library init and destroy
1591fc98642SEugene Zhulenev // functions, we'll use them to register the library with the execution
1601fc98642SEugene Zhulenev // engine. Otherwise we'll pass library directly to the execution engine.
161c86c96a7SChristian Sigg SmallVector<SmallString<256>, 4> libPaths;
162c86c96a7SChristian Sigg
163c86c96a7SChristian Sigg // Use absolute library path so that gdb can find the symbol table.
164c86c96a7SChristian Sigg transform(
165c86c96a7SChristian Sigg options.clSharedLibs, std::back_inserter(libPaths),
166c86c96a7SChristian Sigg [](std::string libPath) {
167c86c96a7SChristian Sigg SmallString<256> absPath(libPath.begin(), libPath.end());
168c86c96a7SChristian Sigg cantFail(llvm::errorCodeToError(llvm::sys::fs::make_absolute(absPath)));
169c86c96a7SChristian Sigg return absPath;
170c86c96a7SChristian Sigg });
1711fc98642SEugene Zhulenev
1721fc98642SEugene Zhulenev // Libraries that we'll pass to the ExecutionEngine for loading.
1731fc98642SEugene Zhulenev SmallVector<StringRef, 4> executionEngineLibs;
1741fc98642SEugene Zhulenev
1751fc98642SEugene Zhulenev using MlirRunnerInitFn = void (*)(llvm::StringMap<void *> &);
1761fc98642SEugene Zhulenev using MlirRunnerDestroyFn = void (*)();
1771fc98642SEugene Zhulenev
1781fc98642SEugene Zhulenev llvm::StringMap<void *> exportSymbols;
1791fc98642SEugene Zhulenev SmallVector<MlirRunnerDestroyFn> destroyFns;
1801fc98642SEugene Zhulenev
1811fc98642SEugene Zhulenev // Handle libraries that do support mlir-runner init/destroy callbacks.
182c86c96a7SChristian Sigg for (auto &libPath : libPaths) {
183c86c96a7SChristian Sigg auto lib = llvm::sys::DynamicLibrary::getPermanentLibrary(libPath.c_str());
1841fc98642SEugene Zhulenev void *initSym = lib.getAddressOfSymbol("__mlir_runner_init");
1851fc98642SEugene Zhulenev void *destroySim = lib.getAddressOfSymbol("__mlir_runner_destroy");
1861fc98642SEugene Zhulenev
1871fc98642SEugene Zhulenev // Library does not support mlir runner, load it with ExecutionEngine.
1881fc98642SEugene Zhulenev if (!initSym || !destroySim) {
1891fc98642SEugene Zhulenev executionEngineLibs.push_back(libPath);
1901fc98642SEugene Zhulenev continue;
1911fc98642SEugene Zhulenev }
1921fc98642SEugene Zhulenev
1931fc98642SEugene Zhulenev auto initFn = reinterpret_cast<MlirRunnerInitFn>(initSym);
1941fc98642SEugene Zhulenev initFn(exportSymbols);
1951fc98642SEugene Zhulenev
1961fc98642SEugene Zhulenev auto destroyFn = reinterpret_cast<MlirRunnerDestroyFn>(destroySim);
1971fc98642SEugene Zhulenev destroyFns.push_back(destroyFn);
1981fc98642SEugene Zhulenev }
1991fc98642SEugene Zhulenev
2001fc98642SEugene Zhulenev // Build a runtime symbol map from the config and exported symbols.
2011fc98642SEugene Zhulenev auto runtimeSymbolMap = [&](llvm::orc::MangleAndInterner interner) {
2021fc98642SEugene Zhulenev auto symbolMap = config.runtimeSymbolMap ? config.runtimeSymbolMap(interner)
2031fc98642SEugene Zhulenev : llvm::orc::SymbolMap();
2041fc98642SEugene Zhulenev for (auto &exportSymbol : exportSymbols)
2051fc98642SEugene Zhulenev symbolMap[interner(exportSymbol.getKey())] =
2061fc98642SEugene Zhulenev llvm::JITEvaluatedSymbol::fromPointer(exportSymbol.getValue());
2071fc98642SEugene Zhulenev return symbolMap;
2081fc98642SEugene Zhulenev };
2091fc98642SEugene Zhulenev
210a7db3c61SEmilio Cota mlir::ExecutionEngineOptions engineOptions;
211a7db3c61SEmilio Cota engineOptions.llvmModuleBuilder = config.llvmModuleBuilder;
21230846d29SMehdi Amini if (config.transformer)
213a7db3c61SEmilio Cota engineOptions.transformer = config.transformer;
214a7db3c61SEmilio Cota engineOptions.jitCodeGenOptLevel = jitCodeGenOptLevel;
215a7db3c61SEmilio Cota engineOptions.sharedLibPaths = executionEngineLibs;
216b24de9f6SEmilio Cota engineOptions.enableObjectCache = true;
217a7db3c61SEmilio Cota auto expectedEngine = mlir::ExecutionEngine::create(module, engineOptions);
218ec44e089SStephen Neuendorffer if (!expectedEngine)
219ec44e089SStephen Neuendorffer return expectedEngine.takeError();
220ec44e089SStephen Neuendorffer
221ec44e089SStephen Neuendorffer auto engine = std::move(*expectedEngine);
2221fc98642SEugene Zhulenev engine->registerSymbols(runtimeSymbolMap);
223f6c9f6ecSEugene Zhulenev
224106f3074STres Popp auto expectedFPtr = engine->lookupPacked(entryPoint);
225ec44e089SStephen Neuendorffer if (!expectedFPtr)
226ec44e089SStephen Neuendorffer return expectedFPtr.takeError();
227ec44e089SStephen Neuendorffer
228ec44e089SStephen Neuendorffer if (options.dumpObjectFile)
229ec44e089SStephen Neuendorffer engine->dumpToObjectFile(options.objectFilename.empty()
230ec44e089SStephen Neuendorffer ? options.inputFilename + ".o"
231ec44e089SStephen Neuendorffer : options.objectFilename);
232ec44e089SStephen Neuendorffer
233ec44e089SStephen Neuendorffer void (*fptr)(void **) = *expectedFPtr;
234ec44e089SStephen Neuendorffer (*fptr)(args);
235ec44e089SStephen Neuendorffer
2361fc98642SEugene Zhulenev // Run all dynamic library destroy callbacks to prepare for the shutdown.
2371fc98642SEugene Zhulenev llvm::for_each(destroyFns, [](MlirRunnerDestroyFn destroy) { destroy(); });
2381fc98642SEugene Zhulenev
239ec44e089SStephen Neuendorffer return Error::success();
240ec44e089SStephen Neuendorffer }
241ec44e089SStephen Neuendorffer
compileAndExecuteVoidFunction(Options & options,ModuleOp module,StringRef entryPoint,CompileAndExecuteConfig config)242f6c9f6ecSEugene Zhulenev static Error compileAndExecuteVoidFunction(Options &options, ModuleOp module,
24389808ce7SGeorge Mitenkov StringRef entryPoint,
244f6c9f6ecSEugene Zhulenev CompileAndExecuteConfig config) {
245ec44e089SStephen Neuendorffer auto mainFunction = module.lookupSymbol<LLVM::LLVMFuncOp>(entryPoint);
246d1506620SRahul Joshi if (!mainFunction || mainFunction.empty())
24702b6fb21SMehdi Amini return makeStringError("entry point not found");
248ec44e089SStephen Neuendorffer void *empty = nullptr;
2494e01184aSMehdi Amini return compileAndExecute(options, module, entryPoint, std::move(config),
2504e01184aSMehdi Amini &empty);
251ec44e089SStephen Neuendorffer }
252ec44e089SStephen Neuendorffer
253d3ead060SStephen Neuendorffer template <typename Type>
254d3ead060SStephen Neuendorffer Error checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction);
255d3ead060SStephen Neuendorffer template <>
checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)256d3ead060SStephen Neuendorffer Error checkCompatibleReturnType<int32_t>(LLVM::LLVMFuncOp mainFunction) {
2574a3460a7SRiver Riddle auto resultType = mainFunction.getFunctionType()
2588de43b92SAlex Zinenko .cast<LLVM::LLVMFunctionType>()
2598de43b92SAlex Zinenko .getReturnType()
2602230bf99SAlex Zinenko .dyn_cast<IntegerType>();
2612230bf99SAlex Zinenko if (!resultType || resultType.getWidth() != 32)
26202b6fb21SMehdi Amini return makeStringError("only single i32 function result supported");
263d3ead060SStephen Neuendorffer return Error::success();
264d3ead060SStephen Neuendorffer }
265d3ead060SStephen Neuendorffer template <>
checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)266d3ead060SStephen Neuendorffer Error checkCompatibleReturnType<int64_t>(LLVM::LLVMFuncOp mainFunction) {
2674a3460a7SRiver Riddle auto resultType = mainFunction.getFunctionType()
2688de43b92SAlex Zinenko .cast<LLVM::LLVMFunctionType>()
2698de43b92SAlex Zinenko .getReturnType()
2702230bf99SAlex Zinenko .dyn_cast<IntegerType>();
2712230bf99SAlex Zinenko if (!resultType || resultType.getWidth() != 64)
27202b6fb21SMehdi Amini return makeStringError("only single i64 function result supported");
273d3ead060SStephen Neuendorffer return Error::success();
274d3ead060SStephen Neuendorffer }
275d3ead060SStephen Neuendorffer template <>
checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)276d3ead060SStephen Neuendorffer Error checkCompatibleReturnType<float>(LLVM::LLVMFuncOp mainFunction) {
2774a3460a7SRiver Riddle if (!mainFunction.getFunctionType()
2788de43b92SAlex Zinenko .cast<LLVM::LLVMFunctionType>()
2798de43b92SAlex Zinenko .getReturnType()
280dd5165a9SAlex Zinenko .isa<Float32Type>())
28102b6fb21SMehdi Amini return makeStringError("only single f32 function result supported");
282d3ead060SStephen Neuendorffer return Error::success();
283d3ead060SStephen Neuendorffer }
284d3ead060SStephen Neuendorffer template <typename Type>
compileAndExecuteSingleReturnFunction(Options & options,ModuleOp module,StringRef entryPoint,CompileAndExecuteConfig config)285f6c9f6ecSEugene Zhulenev Error compileAndExecuteSingleReturnFunction(Options &options, ModuleOp module,
28689808ce7SGeorge Mitenkov StringRef entryPoint,
287f6c9f6ecSEugene Zhulenev CompileAndExecuteConfig config) {
288ec44e089SStephen Neuendorffer auto mainFunction = module.lookupSymbol<LLVM::LLVMFuncOp>(entryPoint);
289ec44e089SStephen Neuendorffer if (!mainFunction || mainFunction.isExternal())
29002b6fb21SMehdi Amini return makeStringError("entry point not found");
291ec44e089SStephen Neuendorffer
2924a3460a7SRiver Riddle if (mainFunction.getFunctionType()
2934a3460a7SRiver Riddle .cast<LLVM::LLVMFunctionType>()
2944a3460a7SRiver Riddle .getNumParams() != 0)
29502b6fb21SMehdi Amini return makeStringError("function inputs not supported");
296ec44e089SStephen Neuendorffer
297d3ead060SStephen Neuendorffer if (Error error = checkCompatibleReturnType<Type>(mainFunction))
298d3ead060SStephen Neuendorffer return error;
299ec44e089SStephen Neuendorffer
300d3ead060SStephen Neuendorffer Type res;
301ec44e089SStephen Neuendorffer struct {
302ec44e089SStephen Neuendorffer void *data;
303ec44e089SStephen Neuendorffer } data;
304ec44e089SStephen Neuendorffer data.data = &res;
3054e01184aSMehdi Amini if (auto error = compileAndExecute(options, module, entryPoint,
3064e01184aSMehdi Amini std::move(config), (void **)&data))
307ec44e089SStephen Neuendorffer return error;
308ec44e089SStephen Neuendorffer
309ec44e089SStephen Neuendorffer // Intentional printing of the output so we can test.
310ec44e089SStephen Neuendorffer llvm::outs() << res << '\n';
311d3ead060SStephen Neuendorffer
312ec44e089SStephen Neuendorffer return Error::success();
313ec44e089SStephen Neuendorffer }
314ec44e089SStephen Neuendorffer
31589808ce7SGeorge Mitenkov /// Entry point for all CPU runners. Expects the common argc/argv arguments for
316f6c9f6ecSEugene Zhulenev /// standard C++ main functions.
JitRunnerMain(int argc,char ** argv,const DialectRegistry & registry,JitRunnerConfig config)3179a08f760SAlex Zinenko int mlir::JitRunnerMain(int argc, char **argv, const DialectRegistry ®istry,
3189a08f760SAlex Zinenko JitRunnerConfig config) {
319ec44e089SStephen Neuendorffer // Create the options struct containing the command line options for the
320ec44e089SStephen Neuendorffer // runner. This must come before the command line options are parsed.
321ec44e089SStephen Neuendorffer Options options;
322ec44e089SStephen Neuendorffer llvm::cl::ParseCommandLineOptions(argc, argv, "MLIR CPU execution driver\n");
323ec44e089SStephen Neuendorffer
324*b630bafbSRainer Orth if (options.hostSupportsJit) {
325*b630bafbSRainer Orth auto J = llvm::orc::LLJITBuilder().create();
326*b630bafbSRainer Orth if (J)
327*b630bafbSRainer Orth llvm::outs() << "true\n";
328*b630bafbSRainer Orth else {
329*b630bafbSRainer Orth llvm::consumeError(J.takeError());
330*b630bafbSRainer Orth llvm::outs() << "false\n";
331*b630bafbSRainer Orth }
332*b630bafbSRainer Orth return 0;
333*b630bafbSRainer Orth }
334*b630bafbSRainer Orth
335ec44e089SStephen Neuendorffer Optional<unsigned> optLevel = getCommandLineOptLevel(options);
336ec44e089SStephen Neuendorffer SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
337ec44e089SStephen Neuendorffer options.optO0, options.optO1, options.optO2, options.optO3};
338ec44e089SStephen Neuendorffer
3399a08f760SAlex Zinenko MLIRContext context(registry);
340f9dc2b70SMehdi Amini
341ec44e089SStephen Neuendorffer auto m = parseMLIRInput(options.inputFilename, &context);
342ec44e089SStephen Neuendorffer if (!m) {
343ec44e089SStephen Neuendorffer llvm::errs() << "could not parse the input IR\n";
344ec44e089SStephen Neuendorffer return 1;
345ec44e089SStephen Neuendorffer }
346ec44e089SStephen Neuendorffer
347f6c9f6ecSEugene Zhulenev if (config.mlirTransformer)
348f6c9f6ecSEugene Zhulenev if (failed(config.mlirTransformer(m.get())))
349ec44e089SStephen Neuendorffer return EXIT_FAILURE;
350ec44e089SStephen Neuendorffer
351ec44e089SStephen Neuendorffer auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
352ec44e089SStephen Neuendorffer if (!tmBuilderOrError) {
353ec44e089SStephen Neuendorffer llvm::errs() << "Failed to create a JITTargetMachineBuilder for the host\n";
354ec44e089SStephen Neuendorffer return EXIT_FAILURE;
355ec44e089SStephen Neuendorffer }
356ec44e089SStephen Neuendorffer auto tmOrError = tmBuilderOrError->createTargetMachine();
357ec44e089SStephen Neuendorffer if (!tmOrError) {
358ec44e089SStephen Neuendorffer llvm::errs() << "Failed to create a TargetMachine for the host\n";
359ec44e089SStephen Neuendorffer return EXIT_FAILURE;
360ec44e089SStephen Neuendorffer }
361ec44e089SStephen Neuendorffer
362f6c9f6ecSEugene Zhulenev CompileAndExecuteConfig compileAndExecuteConfig;
3637ccd026cSArthur Eubanks if (optLevel) {
3647ccd026cSArthur Eubanks compileAndExecuteConfig.transformer = mlir::makeOptimizingTransformer(
3657ccd026cSArthur Eubanks *optLevel, /*sizeLevel=*/0, /*targetMachine=*/tmOrError->get());
3667ccd026cSArthur Eubanks }
367f6c9f6ecSEugene Zhulenev compileAndExecuteConfig.llvmModuleBuilder = config.llvmModuleBuilder;
368f6c9f6ecSEugene Zhulenev compileAndExecuteConfig.runtimeSymbolMap = config.runtimesymbolMap;
369f6c9f6ecSEugene Zhulenev
370ec44e089SStephen Neuendorffer // Get the function used to compile and execute the module.
371ec44e089SStephen Neuendorffer using CompileAndExecuteFnT =
372f6c9f6ecSEugene Zhulenev Error (*)(Options &, ModuleOp, StringRef, CompileAndExecuteConfig);
373ec44e089SStephen Neuendorffer auto compileAndExecuteFn =
374cc83dc19SChristian Sigg StringSwitch<CompileAndExecuteFnT>(options.mainFuncType.getValue())
375d3ead060SStephen Neuendorffer .Case("i32", compileAndExecuteSingleReturnFunction<int32_t>)
376d3ead060SStephen Neuendorffer .Case("i64", compileAndExecuteSingleReturnFunction<int64_t>)
377d3ead060SStephen Neuendorffer .Case("f32", compileAndExecuteSingleReturnFunction<float>)
378ec44e089SStephen Neuendorffer .Case("void", compileAndExecuteVoidFunction)
379ec44e089SStephen Neuendorffer .Default(nullptr);
380ec44e089SStephen Neuendorffer
381f6c9f6ecSEugene Zhulenev Error error = compileAndExecuteFn
382f6c9f6ecSEugene Zhulenev ? compileAndExecuteFn(options, m.get(),
383f6c9f6ecSEugene Zhulenev options.mainFuncName.getValue(),
384f6c9f6ecSEugene Zhulenev compileAndExecuteConfig)
38502b6fb21SMehdi Amini : makeStringError("unsupported function type");
386ec44e089SStephen Neuendorffer
387ec44e089SStephen Neuendorffer int exitCode = EXIT_SUCCESS;
388ec44e089SStephen Neuendorffer llvm::handleAllErrors(std::move(error),
389ec44e089SStephen Neuendorffer [&exitCode](const llvm::ErrorInfoBase &info) {
390ec44e089SStephen Neuendorffer llvm::errs() << "Error: ";
391ec44e089SStephen Neuendorffer info.log(llvm::errs());
392ec44e089SStephen Neuendorffer llvm::errs() << '\n';
393ec44e089SStephen Neuendorffer exitCode = EXIT_FAILURE;
394ec44e089SStephen Neuendorffer });
395ec44e089SStephen Neuendorffer
396ec44e089SStephen Neuendorffer return exitCode;
397ec44e089SStephen Neuendorffer }
398