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 &registry,
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