28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
30#include "llvm/ExecutionEngine/Orc/LLJIT.h"
31#include "llvm/IR/IRBuilder.h"
32#include "llvm/IR/LLVMContext.h"
33#include "llvm/IR/LegacyPassNameParser.h"
34#include "llvm/Support/CommandLine.h"
35#include "llvm/Support/Debug.h"
36#include "llvm/Support/FileUtilities.h"
37#include "llvm/Support/LibraryOptionsContext.h"
38#include "llvm/Support/SourceMgr.h"
39#include "llvm/Support/StringSaver.h"
40#include "llvm/Support/ToolOutputFile.h"
46#define DEBUG_TYPE "jit-runner"
55 llvm::cl::opt<std::string> inputFilename{llvm::cl::Positional,
56 llvm::cl::desc(
"<input file>"),
58 llvm::cl::opt<std::string> mainFuncName{
59 "e", llvm::cl::desc(
"The function to be called"),
60 llvm::cl::value_desc(
"<function name>"), llvm::cl::init(
"main")};
61 llvm::cl::opt<std::string> mainFuncType{
63 llvm::cl::desc(
"Textual description of the function type to be called"),
64 llvm::cl::value_desc(
"f32 | i32 | i64 | void"), llvm::cl::init(
"f32")};
66 llvm::cl::OptionCategory optFlags{
"opt-like flags"};
69 llvm::cl::opt<bool> optO0{
"O0",
70 llvm::cl::desc(
"Run opt passes and codegen at O0"),
71 llvm::cl::cat(optFlags)};
72 llvm::cl::opt<bool> optO1{
"O1",
73 llvm::cl::desc(
"Run opt passes and codegen at O1"),
74 llvm::cl::cat(optFlags)};
75 llvm::cl::opt<bool> optO2{
"O2",
76 llvm::cl::desc(
"Run opt passes and codegen at O2"),
77 llvm::cl::cat(optFlags)};
78 llvm::cl::opt<bool> optO3{
"O3",
79 llvm::cl::desc(
"Run opt passes and codegen at O3"),
80 llvm::cl::cat(optFlags)};
82 llvm::cl::list<std::string> mAttrs{
83 "mattr", llvm::cl::MiscFlags::CommaSeparated,
84 llvm::cl::desc(
"Target specific attributes (-mattr=help for details)"),
85 llvm::cl::value_desc(
"a1,+a2,-a3,..."), llvm::cl::cat(optFlags)};
87 llvm::cl::opt<std::string> mArch{
89 llvm::cl::desc(
"Architecture to generate code for (see --version)")};
91 llvm::cl::OptionCategory clOptionsCategory{
"linking options"};
92 llvm::cl::list<std::string> clSharedLibs{
93 "shared-libs", llvm::cl::desc(
"Libraries to link dynamically"),
94 llvm::cl::MiscFlags::CommaSeparated, llvm::cl::cat(clOptionsCategory)};
97 llvm::cl::opt<bool> dumpObjectFile{
99 llvm::cl::desc(
"Dump JITted-compiled object to file specified with "
100 "-object-filename (<input file>.o by default).")};
102 llvm::cl::opt<std::string> objectFilename{
104 llvm::cl::desc(
"Dump JITted-compiled object to file <input file>.o")};
106 llvm::cl::opt<bool> hostSupportsJit{
"host-supports-jit",
107 llvm::cl::desc(
"Report host JIT support"),
110 llvm::cl::opt<bool> noImplicitModule{
111 "no-implicit-module",
113 "Disable implicit addition of a top-level module op during parsing"),
114 llvm::cl::init(
false)};
117struct CompileAndExecuteConfig {
119 const llvm::cl::LibraryOptionsContext *libraryOptions =
nullptr;
122 std::function<llvm::Error(llvm::Module *)> transformer;
127 llvm::LLVMContext &)>
139 bool insertImplicitModule,
142 std::string errorMessage;
145 llvm::errs() << errorMessage <<
"\n";
149 auto sourceMgr = std::make_shared<llvm::SourceMgr>();
150 sourceMgr->AddNewSourceBuffer(std::move(file), SMLoc());
156 llvm::errs() <<
"Error: top-level op must be a symbol table.\n";
163 return llvm::make_error<llvm::StringError>(message.str(),
164 llvm::inconvertibleErrorCode());
168 std::optional<unsigned> optLevel;
173 for (
unsigned j = 0;
j < 4; ++
j) {
174 auto &flag = optFlags[
j].get();
186 CompileAndExecuteConfig config,
void **args,
187 std::unique_ptr<llvm::TargetMachine> tm =
nullptr) {
188 std::optional<llvm::CodeGenOptLevel> jitCodeGenOptLevel;
190 jitCodeGenOptLevel =
static_cast<llvm::CodeGenOptLevel
>(*clOptLevel);
198 if (config.transformer)
203 auto expectedEngine =
206 return expectedEngine.takeError();
208 auto engine = std::move(*expectedEngine);
210 engine->initialize();
212 auto expectedFPtr = engine->lookupPacked(entryPoint);
214 return expectedFPtr.takeError();
217 engine->dumpToObjectFile(
options.objectFilename.empty()
221 void (*fptr)(
void **) = *expectedFPtr;
224 return Error::success();
229 CompileAndExecuteConfig config, std::unique_ptr<llvm::TargetMachine> tm) {
230 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
232 if (!mainFunction || mainFunction.isExternal())
235 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
236 .getNumParams() != 0)
238 "JIT can't invoke a main function expecting arguments");
240 auto resultType = dyn_cast<LLVM::LLVMVoidType>(
241 mainFunction.getFunctionType().getReturnType());
245 void *empty =
nullptr;
247 &empty, std::move(tm));
250template <
typename Type>
254 auto resultType = dyn_cast<IntegerType>(
255 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
257 if (!resultType || resultType.getWidth() != 32)
259 return Error::success();
263 auto resultType = dyn_cast<IntegerType>(
264 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
266 if (!resultType || resultType.getWidth() != 64)
268 return Error::success();
272 if (!isa<Float32Type>(
273 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
276 return Error::success();
278template <
typename Type>
281 CompileAndExecuteConfig config, std::unique_ptr<llvm::TargetMachine> tm) {
282 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
284 if (!mainFunction || mainFunction.isExternal())
287 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
288 .getNumParams() != 0)
290 "JIT can't invoke a main function expecting arguments");
302 (
void **)&data, std::move(tm)))
306 llvm::outs() << res <<
'\n';
308 return Error::success();
315 llvm::ExitOnError exitOnErr;
320 llvm::cl::LibraryOptionsContext libraryOptions;
321 llvm::cl::parseCommandLineOptions(libraryOptions,
ArrayRef(argv, argc),
322 "MLIR CPU execution driver\n");
325 auto j = llvm::orc::LLJITBuilder().create();
327 llvm::outs() <<
"true\n";
329 llvm::outs() <<
"false\n";
330 exitOnErr(
j.takeError());
344 llvm::errs() <<
"could not parse the input IR\n";
353 auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
354 if (!tmBuilderOrError) {
355 llvm::errs() <<
"Failed to create a JITTargetMachineBuilder for the host\n";
360 llvm::SubtargetFeatures features;
362 for (StringRef attr :
options.mAttrs)
363 features.AddFeature(attr);
364 tmBuilderOrError->addFeatures(features.getFeatures());
368 tmBuilderOrError->getTargetTriple().setArchName(
options.mArch);
372 tmBuilderOrError->getOptions().MCOptions.LibraryOptions = &libraryOptions;
373 auto tmOrError = tmBuilderOrError->createTargetMachine();
376 llvm::errs() <<
"Failed to create a TargetMachine for the host\n";
377 exitOnErr(tmOrError.takeError());
381 llvm::dbgs() <<
" JITTargetMachineBuilder is "
382 << llvm::orc::JITTargetMachineBuilderPrinter(*tmBuilderOrError,
386 CompileAndExecuteConfig compileAndExecuteConfig;
387 compileAndExecuteConfig.libraryOptions = &libraryOptions;
390 *optLevel, 0, tmOrError->get());
396 using CompileAndExecuteFnT =
397 Error (*)(Options &,
Operation *, StringRef, CompileAndExecuteConfig,
398 std::unique_ptr<llvm::TargetMachine> tm);
399 auto compileAndExecuteFn =
407 Error error = compileAndExecuteFn
408 ? compileAndExecuteFn(
410 compileAndExecuteConfig, std::move(tmOrError.get()))
413 int exitCode = EXIT_SUCCESS;
414 llvm::handleAllErrors(std::move(error),
415 [&exitCode](
const llvm::ErrorInfoBase &info) {
416 llvm::errs() <<
"Error: ";
417 info.log(llvm::errs());
418 llvm::errs() <<
'\n';
419 exitCode = EXIT_FAILURE;
Error checkCompatibleReturnType< int64_t >(LLVM::LLVMFuncOp mainFunction)
Error checkCompatibleReturnType(LLVM::LLVMFuncOp mainFunction)
static Error compileAndExecute(Options &options, Operation *module, StringRef entryPoint, CompileAndExecuteConfig config, void **args, std::unique_ptr< llvm::TargetMachine > tm=nullptr)
static OwningOpRef< Operation * > parseMLIRInput(StringRef inputFilename, bool insertImplicitModule, MLIRContext *context)
static Error compileAndExecuteVoidFunction(Options &options, Operation *module, StringRef entryPoint, CompileAndExecuteConfig config, std::unique_ptr< llvm::TargetMachine > tm)
Error checkCompatibleReturnType< float >(LLVM::LLVMFuncOp mainFunction)
static Error compileAndExecuteSingleReturnFunction(Options &options, Operation *module, StringRef entryPoint, CompileAndExecuteConfig config, std::unique_ptr< llvm::TargetMachine > tm)
static Error makeStringError(const Twine &message)
static std::optional< unsigned > getCommandLineOptLevel(Options &options)
Error checkCompatibleReturnType< int32_t >(LLVM::LLVMFuncOp mainFunction)
static llvm::ManagedStatic< PassManagerOptions > options
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
static llvm::Expected< std::unique_ptr< ExecutionEngine > > create(Operation *op, const ExecutionEngineOptions &options={}, std::unique_ptr< llvm::TargetMachine > tm=nullptr)
Creates an execution engine for the given MLIR IR.
MLIRContext is the top-level object for a collection of MLIR operations.
A trait used to provide symbol table functionalities to a region operation.
Operation is the basic unit of execution within MLIR.
This class acts as an owning reference to an op, and will automatically destroy the held op on destru...
OpTy get() const
Allow accessing the internal op.
static Operation * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Include the generated interface declarations.
std::function< llvm::Error(llvm::Module *)> makeOptimizingTransformer(unsigned optLevel, unsigned sizeLevel, llvm::TargetMachine *targetMachine)
Create a module transformer function for MLIR ExecutionEngine that runs LLVM IR passes corresponding ...
int JitRunnerMain(int argc, char **argv, const DialectRegistry ®istry, JitRunnerConfig config={})
Entry point for all CPU runners.
std::unique_ptr< llvm::MemoryBuffer > openInputFile(llvm::StringRef inputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for reading.
OwningOpRef< Operation * > parseSourceFileForTool(const std::shared_ptr< llvm::SourceMgr > &sourceMgr, const ParserConfig &config, bool insertImplicitModule)
This parses the file specified by the indicated SourceMgr.
llvm::StringSwitch< T, R > StringSwitch
llvm::function_ref< std::unique_ptr< llvm::Module >(Operation *, llvm::LLVMContext &)> llvmModuleBuilder
If llvmModuleBuilder is provided, it will be used to create an LLVM module from the given MLIR IR.
std::optional< llvm::CodeGenOptLevel > jitCodeGenOptLevel
jitCodeGenOptLevel, when provided, is used as the optimization level for target code generation.
ArrayRef< StringRef > sharedLibPaths
If sharedLibPaths are provided, the underlying JIT-compilation will open and link the shared librarie...
bool enableObjectDump
If enableObjectCache is set, the JIT compiler will create one to store the object generated for the g...
const llvm::cl::LibraryOptionsContext * libraryOptions
Library options for the LLVMContext and the default TargetMachine.
llvm::function_ref< llvm::Error(llvm::Module *)> transformer
If transformer is provided, it will be called on the LLVM module during JIT-compilation and can be us...
Configuration to override functionality of the JitRunner.
llvm::function_ref< llvm::LogicalResult(mlir::Operation *, JitRunnerOptions &options)> mlirTransformer
MLIR transformer applied after parsing the input into MLIR IR and before passing the MLIR IR to the E...
llvm::function_ref< llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)> runtimesymbolMap
A callback to register symbols with ExecutionEngine at runtime.
llvm::function_ref< std::unique_ptr< llvm::Module >(Operation *, llvm::LLVMContext &)> llvmModuleBuilder
A custom function that is passed to ExecutionEngine.
JitRunner command line options used by JitRunnerConfig methods.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.