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"
2617dbd80fSEmilio Cota #include "mlir/Tools/ParseUtilities.h"
27ec44e089SStephen Neuendorffer
28ec44e089SStephen Neuendorffer #include "llvm/ADT/STLExtras.h"
29ec44e089SStephen Neuendorffer #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
30ca98e0ddSRainer Orth #include "llvm/ExecutionEngine/Orc/LLJIT.h"
31ec44e089SStephen Neuendorffer #include "llvm/IR/IRBuilder.h"
32ec44e089SStephen Neuendorffer #include "llvm/IR/LLVMContext.h"
33ec44e089SStephen Neuendorffer #include "llvm/IR/LegacyPassNameParser.h"
34ec44e089SStephen Neuendorffer #include "llvm/Support/CommandLine.h"
35fb0b035eSAndrzej Warzynski #include "llvm/Support/Debug.h"
36ec44e089SStephen Neuendorffer #include "llvm/Support/FileUtilities.h"
37ec44e089SStephen Neuendorffer #include "llvm/Support/SourceMgr.h"
38ec44e089SStephen Neuendorffer #include "llvm/Support/StringSaver.h"
39ec44e089SStephen Neuendorffer #include "llvm/Support/ToolOutputFile.h"
40d3ead060SStephen Neuendorffer #include <cstdint>
41ec44e089SStephen Neuendorffer #include <numeric>
42a1fe1f5fSKazu Hirata #include <optional>
43fb0b035eSAndrzej Warzynski #include <utility>
44fb0b035eSAndrzej Warzynski
45fb0b035eSAndrzej Warzynski #define DEBUG_TYPE "jit-runner"
46ec44e089SStephen Neuendorffer
47ec44e089SStephen Neuendorffer using namespace mlir;
48ec44e089SStephen Neuendorffer using llvm::Error;
49ec44e089SStephen Neuendorffer
50ec44e089SStephen Neuendorffer namespace {
51ec44e089SStephen Neuendorffer /// This options struct prevents the need for global static initializers, and
52ec44e089SStephen Neuendorffer /// is only initialized if the JITRunner is invoked.
53ec44e089SStephen Neuendorffer struct Options {
54ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> inputFilename{llvm::cl::Positional,
55ec44e089SStephen Neuendorffer llvm::cl::desc("<input file>"),
56ec44e089SStephen Neuendorffer llvm::cl::init("-")};
57ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> mainFuncName{
58ec44e089SStephen Neuendorffer "e", llvm::cl::desc("The function to be called"),
59ec44e089SStephen Neuendorffer llvm::cl::value_desc("<function name>"), llvm::cl::init("main")};
60ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> mainFuncType{
61ec44e089SStephen Neuendorffer "entry-point-result",
62ec44e089SStephen Neuendorffer llvm::cl::desc("Textual description of the function type to be called"),
63d3ead060SStephen Neuendorffer llvm::cl::value_desc("f32 | i32 | i64 | void"), llvm::cl::init("f32")};
64ec44e089SStephen Neuendorffer
65ec44e089SStephen Neuendorffer llvm::cl::OptionCategory optFlags{"opt-like flags"};
66ec44e089SStephen Neuendorffer
67ec44e089SStephen Neuendorffer // CLI variables for -On options.
68ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO0{"O0",
69ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O0"),
70ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
71ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO1{"O1",
72ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O1"),
73ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
74ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO2{"O2",
75ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O2"),
76ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
77ec44e089SStephen Neuendorffer llvm::cl::opt<bool> optO3{"O3",
78ec44e089SStephen Neuendorffer llvm::cl::desc("Run opt passes and codegen at O3"),
79ec44e089SStephen Neuendorffer llvm::cl::cat(optFlags)};
80ec44e089SStephen Neuendorffer
81fb0b035eSAndrzej Warzynski llvm::cl::list<std::string> mAttrs{
82fb0b035eSAndrzej Warzynski "mattr", llvm::cl::MiscFlags::CommaSeparated,
83fb0b035eSAndrzej Warzynski llvm::cl::desc("Target specific attributes (-mattr=help for details)"),
84fb0b035eSAndrzej Warzynski llvm::cl::value_desc("a1,+a2,-a3,..."), llvm::cl::cat(optFlags)};
85fb0b035eSAndrzej Warzynski
86fb0b035eSAndrzej Warzynski llvm::cl::opt<std::string> mArch{
87fb0b035eSAndrzej Warzynski "march",
88fb0b035eSAndrzej Warzynski llvm::cl::desc("Architecture to generate code for (see --version)")};
89fb0b035eSAndrzej Warzynski
90ec44e089SStephen Neuendorffer llvm::cl::OptionCategory clOptionsCategory{"linking options"};
91ec44e089SStephen Neuendorffer llvm::cl::list<std::string> clSharedLibs{
92ec44e089SStephen Neuendorffer "shared-libs", llvm::cl::desc("Libraries to link dynamically"),
93d86a206fSFangrui Song llvm::cl::MiscFlags::CommaSeparated, llvm::cl::cat(clOptionsCategory)};
94ec44e089SStephen Neuendorffer
95ec44e089SStephen Neuendorffer /// CLI variables for debugging.
96ec44e089SStephen Neuendorffer llvm::cl::opt<bool> dumpObjectFile{
97ec44e089SStephen Neuendorffer "dump-object-file",
98ec44e089SStephen Neuendorffer llvm::cl::desc("Dump JITted-compiled object to file specified with "
99ec44e089SStephen Neuendorffer "-object-filename (<input file>.o by default).")};
100ec44e089SStephen Neuendorffer
101ec44e089SStephen Neuendorffer llvm::cl::opt<std::string> objectFilename{
102ec44e089SStephen Neuendorffer "object-filename",
103ec44e089SStephen Neuendorffer llvm::cl::desc("Dump JITted-compiled object to file <input file>.o")};
104ca98e0ddSRainer Orth
105ca98e0ddSRainer Orth llvm::cl::opt<bool> hostSupportsJit{"host-supports-jit",
106ca98e0ddSRainer Orth llvm::cl::desc("Report host JIT support"),
107ca98e0ddSRainer Orth llvm::cl::Hidden};
108200889fbSrkayaith
109200889fbSrkayaith llvm::cl::opt<bool> noImplicitModule{
110200889fbSrkayaith "no-implicit-module",
111200889fbSrkayaith llvm::cl::desc(
112200889fbSrkayaith "Disable implicit addition of a top-level module op during parsing"),
113200889fbSrkayaith llvm::cl::init(false)};
114ec44e089SStephen Neuendorffer };
115f6c9f6ecSEugene Zhulenev
116f6c9f6ecSEugene Zhulenev struct CompileAndExecuteConfig {
117f6c9f6ecSEugene Zhulenev /// LLVM module transformer that is passed to ExecutionEngine.
11807db69efSMehdi Amini std::function<llvm::Error(llvm::Module *)> transformer;
119f6c9f6ecSEugene Zhulenev
120f6c9f6ecSEugene Zhulenev /// A custom function that is passed to ExecutionEngine. It processes MLIR
121f6c9f6ecSEugene Zhulenev /// module and creates LLVM IR module.
122200889fbSrkayaith llvm::function_ref<std::unique_ptr<llvm::Module>(Operation *,
123f6c9f6ecSEugene Zhulenev llvm::LLVMContext &)>
124f6c9f6ecSEugene Zhulenev llvmModuleBuilder;
125f6c9f6ecSEugene Zhulenev
126f6c9f6ecSEugene Zhulenev /// A custom function that is passed to ExecutinEngine to register symbols at
127f6c9f6ecSEugene Zhulenev /// runtime.
128f6c9f6ecSEugene Zhulenev llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
129f6c9f6ecSEugene Zhulenev runtimeSymbolMap;
130f6c9f6ecSEugene Zhulenev };
131f6c9f6ecSEugene Zhulenev
132be0a7e9fSMehdi Amini } // namespace
133ec44e089SStephen Neuendorffer
parseMLIRInput(StringRef inputFilename,bool insertImplicitModule,MLIRContext * context)134200889fbSrkayaith static OwningOpRef<Operation *> parseMLIRInput(StringRef inputFilename,
135200889fbSrkayaith bool insertImplicitModule,
136ec44e089SStephen Neuendorffer MLIRContext *context) {
137ec44e089SStephen Neuendorffer // Set up the input file.
138ec44e089SStephen Neuendorffer std::string errorMessage;
139ec44e089SStephen Neuendorffer auto file = openInputFile(inputFilename, &errorMessage);
140ec44e089SStephen Neuendorffer if (!file) {
141ec44e089SStephen Neuendorffer llvm::errs() << errorMessage << "\n";
142ec44e089SStephen Neuendorffer return nullptr;
143ec44e089SStephen Neuendorffer }
144ec44e089SStephen Neuendorffer
14518546ff8SRiver Riddle auto sourceMgr = std::make_shared<llvm::SourceMgr>();
14618546ff8SRiver Riddle sourceMgr->AddNewSourceBuffer(std::move(file), SMLoc());
147200889fbSrkayaith OwningOpRef<Operation *> module =
148200889fbSrkayaith parseSourceFileForTool(sourceMgr, context, insertImplicitModule);
149200889fbSrkayaith if (!module)
150200889fbSrkayaith return nullptr;
151200889fbSrkayaith if (!module.get()->hasTrait<OpTrait::SymbolTable>()) {
152200889fbSrkayaith llvm::errs() << "Error: top-level op must be a symbol table.\n";
153200889fbSrkayaith return nullptr;
154200889fbSrkayaith }
155200889fbSrkayaith return module;
156ec44e089SStephen Neuendorffer }
157ec44e089SStephen Neuendorffer
makeStringError(const Twine & message)15802b6fb21SMehdi Amini static inline Error makeStringError(const Twine &message) {
159ec44e089SStephen Neuendorffer return llvm::make_error<llvm::StringError>(message.str(),
160ec44e089SStephen Neuendorffer llvm::inconvertibleErrorCode());
161ec44e089SStephen Neuendorffer }
162ec44e089SStephen Neuendorffer
getCommandLineOptLevel(Options & options)1630a81ace0SKazu Hirata static std::optional<unsigned> getCommandLineOptLevel(Options &options) {
1640a81ace0SKazu Hirata std::optional<unsigned> optLevel;
165ec44e089SStephen Neuendorffer SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
166ec44e089SStephen Neuendorffer options.optO0, options.optO1, options.optO2, options.optO3};
167ec44e089SStephen Neuendorffer
168ec44e089SStephen Neuendorffer // Determine if there is an optimization flag present.
169ec44e089SStephen Neuendorffer for (unsigned j = 0; j < 4; ++j) {
170ec44e089SStephen Neuendorffer auto &flag = optFlags[j].get();
171ec44e089SStephen Neuendorffer if (flag) {
172ec44e089SStephen Neuendorffer optLevel = j;
173ec44e089SStephen Neuendorffer break;
174ec44e089SStephen Neuendorffer }
175ec44e089SStephen Neuendorffer }
176ec44e089SStephen Neuendorffer return optLevel;
177ec44e089SStephen Neuendorffer }
178ec44e089SStephen Neuendorffer
179ec44e089SStephen Neuendorffer // JIT-compile the given module and run "entryPoint" with "args" as arguments.
180fb0b035eSAndrzej Warzynski static Error
compileAndExecute(Options & options,Operation * module,StringRef entryPoint,CompileAndExecuteConfig config,void ** args,std::unique_ptr<llvm::TargetMachine> tm=nullptr)181fb0b035eSAndrzej Warzynski compileAndExecute(Options &options, Operation *module, StringRef entryPoint,
182fb0b035eSAndrzej Warzynski CompileAndExecuteConfig config, void **args,
183fb0b035eSAndrzej Warzynski std::unique_ptr<llvm::TargetMachine> tm = nullptr) {
184*0a1aa6cdSArthur Eubanks std::optional<llvm::CodeGenOptLevel> jitCodeGenOptLevel;
185ec44e089SStephen Neuendorffer if (auto clOptLevel = getCommandLineOptLevel(options))
186*0a1aa6cdSArthur Eubanks jitCodeGenOptLevel = static_cast<llvm::CodeGenOptLevel>(*clOptLevel);
1871fc98642SEugene Zhulenev
1880b3841ebSIngo Müller SmallVector<StringRef, 4> sharedLibs(options.clSharedLibs.begin(),
1890b3841ebSIngo Müller options.clSharedLibs.end());
1901fc98642SEugene Zhulenev
191a7db3c61SEmilio Cota mlir::ExecutionEngineOptions engineOptions;
192a7db3c61SEmilio Cota engineOptions.llvmModuleBuilder = config.llvmModuleBuilder;
19330846d29SMehdi Amini if (config.transformer)
194a7db3c61SEmilio Cota engineOptions.transformer = config.transformer;
195a7db3c61SEmilio Cota engineOptions.jitCodeGenOptLevel = jitCodeGenOptLevel;
1960b3841ebSIngo Müller engineOptions.sharedLibPaths = sharedLibs;
19795c083f5SDenys Shabalin engineOptions.enableObjectDump = true;
198fb0b035eSAndrzej Warzynski auto expectedEngine =
199fb0b035eSAndrzej Warzynski mlir::ExecutionEngine::create(module, engineOptions, std::move(tm));
200ec44e089SStephen Neuendorffer if (!expectedEngine)
201ec44e089SStephen Neuendorffer return expectedEngine.takeError();
202ec44e089SStephen Neuendorffer
203ec44e089SStephen Neuendorffer auto engine = std::move(*expectedEngine);
204f6c9f6ecSEugene Zhulenev
205106f3074STres Popp auto expectedFPtr = engine->lookupPacked(entryPoint);
206ec44e089SStephen Neuendorffer if (!expectedFPtr)
207ec44e089SStephen Neuendorffer return expectedFPtr.takeError();
208ec44e089SStephen Neuendorffer
209ec44e089SStephen Neuendorffer if (options.dumpObjectFile)
210ec44e089SStephen Neuendorffer engine->dumpToObjectFile(options.objectFilename.empty()
211ec44e089SStephen Neuendorffer ? options.inputFilename + ".o"
212ec44e089SStephen Neuendorffer : options.objectFilename);
213ec44e089SStephen Neuendorffer
214ec44e089SStephen Neuendorffer void (*fptr)(void **) = *expectedFPtr;
215ec44e089SStephen Neuendorffer (*fptr)(args);
216ec44e089SStephen Neuendorffer
217ec44e089SStephen Neuendorffer return Error::success();
218ec44e089SStephen Neuendorffer }
219ec44e089SStephen Neuendorffer
compileAndExecuteVoidFunction(Options & options,Operation * module,StringRef entryPoint,CompileAndExecuteConfig config,std::unique_ptr<llvm::TargetMachine> tm)220fb0b035eSAndrzej Warzynski static Error compileAndExecuteVoidFunction(
221fb0b035eSAndrzej Warzynski Options &options, Operation *module, StringRef entryPoint,
222fb0b035eSAndrzej Warzynski CompileAndExecuteConfig config, std::unique_ptr<llvm::TargetMachine> tm) {
223200889fbSrkayaith auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
224200889fbSrkayaith SymbolTable::lookupSymbolIn(module, entryPoint));
225d1506620SRahul Joshi if (!mainFunction || mainFunction.empty())
22602b6fb21SMehdi Amini return makeStringError("entry point not found");
227fb27d542SCullen Rhodes
228fb27d542SCullen Rhodes auto resultType = dyn_cast<LLVM::LLVMVoidType>(
229fb27d542SCullen Rhodes mainFunction.getFunctionType().getReturnType());
230fb27d542SCullen Rhodes if (!resultType)
231fb27d542SCullen Rhodes return makeStringError("expected void function");
232fb27d542SCullen Rhodes
233ec44e089SStephen Neuendorffer void *empty = nullptr;
2344e01184aSMehdi Amini return compileAndExecute(options, module, entryPoint, std::move(config),
235fb0b035eSAndrzej Warzynski &empty, std::move(tm));
236ec44e089SStephen Neuendorffer }
237ec44e089SStephen Neuendorffer
238d3ead060SStephen Neuendorffer template <typename Type>
239d3ead060SStephen Neuendorffer Error checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction);
240d3ead060SStephen Neuendorffer template <>
checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)241d3ead060SStephen Neuendorffer Error checkCompatibleReturnType<int32_t>(LLVM::LLVMFuncOp mainFunction) {
2425550c821STres Popp auto resultType = dyn_cast<IntegerType>(
2435550c821STres Popp cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
2445550c821STres Popp .getReturnType());
2452230bf99SAlex Zinenko if (!resultType || resultType.getWidth() != 32)
24602b6fb21SMehdi Amini return makeStringError("only single i32 function result supported");
247d3ead060SStephen Neuendorffer return Error::success();
248d3ead060SStephen Neuendorffer }
249d3ead060SStephen Neuendorffer template <>
checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)250d3ead060SStephen Neuendorffer Error checkCompatibleReturnType<int64_t>(LLVM::LLVMFuncOp mainFunction) {
2515550c821STres Popp auto resultType = dyn_cast<IntegerType>(
2525550c821STres Popp cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
2535550c821STres Popp .getReturnType());
2542230bf99SAlex Zinenko if (!resultType || resultType.getWidth() != 64)
25502b6fb21SMehdi Amini return makeStringError("only single i64 function result supported");
256d3ead060SStephen Neuendorffer return Error::success();
257d3ead060SStephen Neuendorffer }
258d3ead060SStephen Neuendorffer template <>
checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)259d3ead060SStephen Neuendorffer Error checkCompatibleReturnType<float>(LLVM::LLVMFuncOp mainFunction) {
2605550c821STres Popp if (!isa<Float32Type>(
2615550c821STres Popp cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
2625550c821STres Popp .getReturnType()))
26302b6fb21SMehdi Amini return makeStringError("only single f32 function result supported");
264d3ead060SStephen Neuendorffer return Error::success();
265d3ead060SStephen Neuendorffer }
266d3ead060SStephen Neuendorffer template <typename Type>
compileAndExecuteSingleReturnFunction(Options & options,Operation * module,StringRef entryPoint,CompileAndExecuteConfig config,std::unique_ptr<llvm::TargetMachine> tm)267fb0b035eSAndrzej Warzynski Error compileAndExecuteSingleReturnFunction(
268fb0b035eSAndrzej Warzynski Options &options, Operation *module, StringRef entryPoint,
269fb0b035eSAndrzej Warzynski CompileAndExecuteConfig config, std::unique_ptr<llvm::TargetMachine> tm) {
270200889fbSrkayaith auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
271200889fbSrkayaith SymbolTable::lookupSymbolIn(module, entryPoint));
272ec44e089SStephen Neuendorffer if (!mainFunction || mainFunction.isExternal())
27302b6fb21SMehdi Amini return makeStringError("entry point not found");
274ec44e089SStephen Neuendorffer
2755550c821STres Popp if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
2764a3460a7SRiver Riddle .getNumParams() != 0)
27702b6fb21SMehdi Amini return makeStringError("function inputs not supported");
278ec44e089SStephen Neuendorffer
279d3ead060SStephen Neuendorffer if (Error error = checkCompatibleReturnType<Type>(mainFunction))
280d3ead060SStephen Neuendorffer return error;
281ec44e089SStephen Neuendorffer
282d3ead060SStephen Neuendorffer Type res;
283ec44e089SStephen Neuendorffer struct {
284ec44e089SStephen Neuendorffer void *data;
285ec44e089SStephen Neuendorffer } data;
286ec44e089SStephen Neuendorffer data.data = &res;
287fb0b035eSAndrzej Warzynski if (auto error =
288fb0b035eSAndrzej Warzynski compileAndExecute(options, module, entryPoint, std::move(config),
289fb0b035eSAndrzej Warzynski (void **)&data, std::move(tm)))
290ec44e089SStephen Neuendorffer return error;
291ec44e089SStephen Neuendorffer
292ec44e089SStephen Neuendorffer // Intentional printing of the output so we can test.
293ec44e089SStephen Neuendorffer llvm::outs() << res << '\n';
294d3ead060SStephen Neuendorffer
295ec44e089SStephen Neuendorffer return Error::success();
296ec44e089SStephen Neuendorffer }
297ec44e089SStephen Neuendorffer
29889808ce7SGeorge Mitenkov /// Entry point for all CPU runners. Expects the common argc/argv arguments for
299f6c9f6ecSEugene Zhulenev /// standard C++ main functions.
JitRunnerMain(int argc,char ** argv,const DialectRegistry & registry,JitRunnerConfig config)3009a08f760SAlex Zinenko int mlir::JitRunnerMain(int argc, char **argv, const DialectRegistry ®istry,
3019a08f760SAlex Zinenko JitRunnerConfig config) {
302fb0b035eSAndrzej Warzynski llvm::ExitOnError exitOnErr;
303fb0b035eSAndrzej Warzynski
304ec44e089SStephen Neuendorffer // Create the options struct containing the command line options for the
305ec44e089SStephen Neuendorffer // runner. This must come before the command line options are parsed.
306ec44e089SStephen Neuendorffer Options options;
307ec44e089SStephen Neuendorffer llvm::cl::ParseCommandLineOptions(argc, argv, "MLIR CPU execution driver\n");
308ec44e089SStephen Neuendorffer
309ca98e0ddSRainer Orth if (options.hostSupportsJit) {
3100969d0deSMehdi Amini auto j = llvm::orc::LLJITBuilder().create();
3110969d0deSMehdi Amini if (j)
312ca98e0ddSRainer Orth llvm::outs() << "true\n";
313ca98e0ddSRainer Orth else {
314ca98e0ddSRainer Orth llvm::outs() << "false\n";
315fb0b035eSAndrzej Warzynski exitOnErr(j.takeError());
316ca98e0ddSRainer Orth }
317ca98e0ddSRainer Orth return 0;
318ca98e0ddSRainer Orth }
319ca98e0ddSRainer Orth
3200a81ace0SKazu Hirata std::optional<unsigned> optLevel = getCommandLineOptLevel(options);
321ec44e089SStephen Neuendorffer SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
322ec44e089SStephen Neuendorffer options.optO0, options.optO1, options.optO2, options.optO3};
323ec44e089SStephen Neuendorffer
3249a08f760SAlex Zinenko MLIRContext context(registry);
325f9dc2b70SMehdi Amini
326200889fbSrkayaith auto m = parseMLIRInput(options.inputFilename, !options.noImplicitModule,
327200889fbSrkayaith &context);
328ec44e089SStephen Neuendorffer if (!m) {
329ec44e089SStephen Neuendorffer llvm::errs() << "could not parse the input IR\n";
330ec44e089SStephen Neuendorffer return 1;
331ec44e089SStephen Neuendorffer }
332ec44e089SStephen Neuendorffer
3331b99e8baSRenato Golin JitRunnerOptions runnerOptions{options.mainFuncName, options.mainFuncType};
334f6c9f6ecSEugene Zhulenev if (config.mlirTransformer)
3351b99e8baSRenato Golin if (failed(config.mlirTransformer(m.get(), runnerOptions)))
336ec44e089SStephen Neuendorffer return EXIT_FAILURE;
337ec44e089SStephen Neuendorffer
338ec44e089SStephen Neuendorffer auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
339ec44e089SStephen Neuendorffer if (!tmBuilderOrError) {
340ec44e089SStephen Neuendorffer llvm::errs() << "Failed to create a JITTargetMachineBuilder for the host\n";
341ec44e089SStephen Neuendorffer return EXIT_FAILURE;
342ec44e089SStephen Neuendorffer }
343fb0b035eSAndrzej Warzynski
344fb0b035eSAndrzej Warzynski // Configure TargetMachine builder based on the command line options
345fb0b035eSAndrzej Warzynski llvm::SubtargetFeatures features;
346fb0b035eSAndrzej Warzynski if (!options.mAttrs.empty()) {
34753be2e0fSUday Bondhugula for (StringRef attr : options.mAttrs)
34853be2e0fSUday Bondhugula features.AddFeature(attr);
349fb0b035eSAndrzej Warzynski tmBuilderOrError->addFeatures(features.getFeatures());
350fb0b035eSAndrzej Warzynski }
351fb0b035eSAndrzej Warzynski
352fb0b035eSAndrzej Warzynski if (!options.mArch.empty()) {
353fb0b035eSAndrzej Warzynski tmBuilderOrError->getTargetTriple().setArchName(options.mArch);
354fb0b035eSAndrzej Warzynski }
355fb0b035eSAndrzej Warzynski
356fb0b035eSAndrzej Warzynski // Build TargetMachine
357ec44e089SStephen Neuendorffer auto tmOrError = tmBuilderOrError->createTargetMachine();
358fb0b035eSAndrzej Warzynski
359ec44e089SStephen Neuendorffer if (!tmOrError) {
360ec44e089SStephen Neuendorffer llvm::errs() << "Failed to create a TargetMachine for the host\n";
361fb0b035eSAndrzej Warzynski exitOnErr(tmOrError.takeError());
362ec44e089SStephen Neuendorffer }
363ec44e089SStephen Neuendorffer
364fb0b035eSAndrzej Warzynski LLVM_DEBUG({
365fb0b035eSAndrzej Warzynski llvm::dbgs() << " JITTargetMachineBuilder is "
366fb0b035eSAndrzej Warzynski << llvm::orc::JITTargetMachineBuilderPrinter(*tmBuilderOrError,
367fb0b035eSAndrzej Warzynski "\n");
368fb0b035eSAndrzej Warzynski });
369fb0b035eSAndrzej Warzynski
370f6c9f6ecSEugene Zhulenev CompileAndExecuteConfig compileAndExecuteConfig;
3717ccd026cSArthur Eubanks if (optLevel) {
3727ccd026cSArthur Eubanks compileAndExecuteConfig.transformer = mlir::makeOptimizingTransformer(
3737ccd026cSArthur Eubanks *optLevel, /*sizeLevel=*/0, /*targetMachine=*/tmOrError->get());
3747ccd026cSArthur Eubanks }
375f6c9f6ecSEugene Zhulenev compileAndExecuteConfig.llvmModuleBuilder = config.llvmModuleBuilder;
376f6c9f6ecSEugene Zhulenev compileAndExecuteConfig.runtimeSymbolMap = config.runtimesymbolMap;
377f6c9f6ecSEugene Zhulenev
378ec44e089SStephen Neuendorffer // Get the function used to compile and execute the module.
379ec44e089SStephen Neuendorffer using CompileAndExecuteFnT =
380fb0b035eSAndrzej Warzynski Error (*)(Options &, Operation *, StringRef, CompileAndExecuteConfig,
381fb0b035eSAndrzej Warzynski std::unique_ptr<llvm::TargetMachine> tm);
382ec44e089SStephen Neuendorffer auto compileAndExecuteFn =
383cc83dc19SChristian Sigg StringSwitch<CompileAndExecuteFnT>(options.mainFuncType.getValue())
384d3ead060SStephen Neuendorffer .Case("i32", compileAndExecuteSingleReturnFunction<int32_t>)
385d3ead060SStephen Neuendorffer .Case("i64", compileAndExecuteSingleReturnFunction<int64_t>)
386d3ead060SStephen Neuendorffer .Case("f32", compileAndExecuteSingleReturnFunction<float>)
387ec44e089SStephen Neuendorffer .Case("void", compileAndExecuteVoidFunction)
388ec44e089SStephen Neuendorffer .Default(nullptr);
389ec44e089SStephen Neuendorffer
390f6c9f6ecSEugene Zhulenev Error error = compileAndExecuteFn
391fb0b035eSAndrzej Warzynski ? compileAndExecuteFn(
392fb0b035eSAndrzej Warzynski options, m.get(), options.mainFuncName.getValue(),
393fb0b035eSAndrzej Warzynski compileAndExecuteConfig, std::move(tmOrError.get()))
39402b6fb21SMehdi Amini : makeStringError("unsupported function type");
395ec44e089SStephen Neuendorffer
396ec44e089SStephen Neuendorffer int exitCode = EXIT_SUCCESS;
397ec44e089SStephen Neuendorffer llvm::handleAllErrors(std::move(error),
398ec44e089SStephen Neuendorffer [&exitCode](const llvm::ErrorInfoBase &info) {
399ec44e089SStephen Neuendorffer llvm::errs() << "Error: ";
400ec44e089SStephen Neuendorffer info.log(llvm::errs());
401ec44e089SStephen Neuendorffer llvm::errs() << '\n';
402ec44e089SStephen Neuendorffer exitCode = EXIT_FAILURE;
403ec44e089SStephen Neuendorffer });
404ec44e089SStephen Neuendorffer
405ec44e089SStephen Neuendorffer return exitCode;
406ec44e089SStephen Neuendorffer }
407