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/SourceMgr.h"
38 #include "llvm/Support/StringSaver.h"
39 #include "llvm/Support/ToolOutputFile.h"
45 #define DEBUG_TYPE "jit-runner"
54 llvm::cl::opt<std::string> inputFilename{llvm::cl::Positional,
55 llvm::cl::desc(
"<input file>"),
57 llvm::cl::opt<std::string> mainFuncName{
58 "e", llvm::cl::desc(
"The function to be called"),
59 llvm::cl::value_desc(
"<function name>"), llvm::cl::init(
"main")};
60 llvm::cl::opt<std::string> mainFuncType{
62 llvm::cl::desc(
"Textual description of the function type to be called"),
63 llvm::cl::value_desc(
"f32 | i32 | i64 | void"), llvm::cl::init(
"f32")};
65 llvm::cl::OptionCategory optFlags{
"opt-like flags"};
68 llvm::cl::opt<bool> optO0{
"O0",
69 llvm::cl::desc(
"Run opt passes and codegen at O0"),
70 llvm::cl::cat(optFlags)};
71 llvm::cl::opt<bool> optO1{
"O1",
72 llvm::cl::desc(
"Run opt passes and codegen at O1"),
73 llvm::cl::cat(optFlags)};
74 llvm::cl::opt<bool> optO2{
"O2",
75 llvm::cl::desc(
"Run opt passes and codegen at O2"),
76 llvm::cl::cat(optFlags)};
77 llvm::cl::opt<bool> optO3{
"O3",
78 llvm::cl::desc(
"Run opt passes and codegen at O3"),
79 llvm::cl::cat(optFlags)};
81 llvm::cl::list<std::string> mAttrs{
82 "mattr", llvm::cl::MiscFlags::CommaSeparated,
83 llvm::cl::desc(
"Target specific attributes (-mattr=help for details)"),
84 llvm::cl::value_desc(
"a1,+a2,-a3,..."), llvm::cl::cat(optFlags)};
86 llvm::cl::opt<std::string> mArch{
88 llvm::cl::desc(
"Architecture to generate code for (see --version)")};
90 llvm::cl::OptionCategory clOptionsCategory{
"linking options"};
91 llvm::cl::list<std::string> clSharedLibs{
92 "shared-libs", llvm::cl::desc(
"Libraries to link dynamically"),
93 llvm::cl::MiscFlags::CommaSeparated, llvm::cl::cat(clOptionsCategory)};
96 llvm::cl::opt<bool> dumpObjectFile{
98 llvm::cl::desc(
"Dump JITted-compiled object to file specified with "
99 "-object-filename (<input file>.o by default).")};
101 llvm::cl::opt<std::string> objectFilename{
103 llvm::cl::desc(
"Dump JITted-compiled object to file <input file>.o")};
105 llvm::cl::opt<bool> hostSupportsJit{
"host-supports-jit",
106 llvm::cl::desc(
"Report host JIT support"),
109 llvm::cl::opt<bool> noImplicitModule{
110 "no-implicit-module",
112 "Disable implicit addition of a top-level module op during parsing"),
113 llvm::cl::init(
false)};
116 struct CompileAndExecuteConfig {
118 std::function<llvm::Error(llvm::Module *)> transformer;
123 llvm::LLVMContext &)>
135 bool insertImplicitModule,
138 std::string errorMessage;
141 llvm::errs() << errorMessage <<
"\n";
145 auto sourceMgr = std::make_shared<llvm::SourceMgr>();
146 sourceMgr->AddNewSourceBuffer(std::move(file), SMLoc());
152 llvm::errs() <<
"Error: top-level op must be a symbol table.\n";
159 return llvm::make_error<llvm::StringError>(message.str(),
160 llvm::inconvertibleErrorCode());
164 std::optional<unsigned> optLevel;
169 for (
unsigned j = 0;
j < 4; ++
j) {
170 auto &flag = optFlags[
j].get();
182 CompileAndExecuteConfig
config,
void **args,
183 std::unique_ptr<llvm::TargetMachine> tm =
nullptr) {
184 std::optional<llvm::CodeGenOptLevel> jitCodeGenOptLevel;
186 jitCodeGenOptLevel =
static_cast<llvm::CodeGenOptLevel
>(*clOptLevel);
198 auto expectedEngine =
201 return expectedEngine.takeError();
203 auto engine = std::move(*expectedEngine);
205 auto expectedFPtr = engine->lookupPacked(entryPoint);
207 return expectedFPtr.takeError();
210 engine->dumpToObjectFile(
options.objectFilename.empty()
214 void (*fptr)(
void **) = *expectedFPtr;
217 return Error::success();
222 CompileAndExecuteConfig
config, std::unique_ptr<llvm::TargetMachine> tm) {
223 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
225 if (!mainFunction || mainFunction.isExternal())
228 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
229 .getNumParams() != 0)
231 "JIT can't invoke a main function expecting arguments");
233 auto resultType = dyn_cast<LLVM::LLVMVoidType>(
234 mainFunction.getFunctionType().getReturnType());
238 void *empty =
nullptr;
240 &empty, std::move(tm));
243 template <
typename Type>
247 auto resultType = dyn_cast<IntegerType>(
248 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
250 if (!resultType || resultType.getWidth() != 32)
252 return Error::success();
256 auto resultType = dyn_cast<IntegerType>(
257 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
259 if (!resultType || resultType.getWidth() != 64)
261 return Error::success();
265 if (!isa<Float32Type>(
266 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
269 return Error::success();
271 template <
typename Type>
274 CompileAndExecuteConfig
config, std::unique_ptr<llvm::TargetMachine> tm) {
275 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
277 if (!mainFunction || mainFunction.isExternal())
280 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
281 .getNumParams() != 0)
283 "JIT can't invoke a main function expecting arguments");
285 if (
Error error = checkCompatibleReturnType<Type>(mainFunction))
295 (
void **)&data, std::move(tm)))
299 llvm::outs() << res <<
'\n';
301 return Error::success();
308 llvm::ExitOnError exitOnErr;
313 llvm::cl::ParseCommandLineOptions(argc, argv,
"MLIR CPU execution driver\n");
316 auto j = llvm::orc::LLJITBuilder().create();
318 llvm::outs() <<
"true\n";
320 llvm::outs() <<
"false\n";
321 exitOnErr(
j.takeError());
335 llvm::errs() <<
"could not parse the input IR\n";
340 if (
config.mlirTransformer)
341 if (failed(
config.mlirTransformer(m.get(), runnerOptions)))
344 auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
345 if (!tmBuilderOrError) {
346 llvm::errs() <<
"Failed to create a JITTargetMachineBuilder for the host\n";
351 llvm::SubtargetFeatures features;
353 for (StringRef attr :
options.mAttrs)
354 features.AddFeature(attr);
355 tmBuilderOrError->addFeatures(features.getFeatures());
359 tmBuilderOrError->getTargetTriple().setArchName(
options.mArch);
363 auto tmOrError = tmBuilderOrError->createTargetMachine();
366 llvm::errs() <<
"Failed to create a TargetMachine for the host\n";
367 exitOnErr(tmOrError.takeError());
371 llvm::dbgs() <<
" JITTargetMachineBuilder is "
372 << llvm::orc::JITTargetMachineBuilderPrinter(*tmBuilderOrError,
376 CompileAndExecuteConfig compileAndExecuteConfig;
379 *optLevel, 0, tmOrError->get());
381 compileAndExecuteConfig.llvmModuleBuilder =
config.llvmModuleBuilder;
382 compileAndExecuteConfig.runtimeSymbolMap =
config.runtimesymbolMap;
385 using CompileAndExecuteFnT =
386 Error (*)(Options &,
Operation *, StringRef, CompileAndExecuteConfig,
387 std::unique_ptr<llvm::TargetMachine> tm);
388 auto compileAndExecuteFn =
390 .Case(
"i32", compileAndExecuteSingleReturnFunction<int32_t>)
391 .Case(
"i64", compileAndExecuteSingleReturnFunction<int64_t>)
392 .Case(
"f32", compileAndExecuteSingleReturnFunction<float>)
396 Error error = compileAndExecuteFn
397 ? compileAndExecuteFn(
399 compileAndExecuteConfig, std::move(tmOrError.get()))
402 int exitCode = EXIT_SUCCESS;
403 llvm::handleAllErrors(std::move(error),
404 [&exitCode](
const llvm::ErrorInfoBase &info) {
405 llvm::errs() <<
"Error: ";
406 info.log(llvm::errs());
407 llvm::errs() <<
'\n';
408 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)
Error compileAndExecuteSingleReturnFunction(Options &options, Operation *module, StringRef entryPoint, CompileAndExecuteConfig config, std::unique_ptr< llvm::TargetMachine > tm)
static Error compileAndExecuteVoidFunction(Options &options, Operation *module, StringRef entryPoint, CompileAndExecuteConfig config, std::unique_ptr< llvm::TargetMachine > tm)
Error checkCompatibleReturnType< float >(LLVM::LLVMFuncOp mainFunction)
static std::optional< unsigned > getCommandLineOptLevel(Options &options)
static Error makeStringError(const Twine &message)
Error checkCompatibleReturnType< int32_t >(LLVM::LLVMFuncOp mainFunction)
static OwningOpRef< Operation * > parseMLIRInput(StringRef inputFilename, bool insertImplicitModule, MLIRContext *context)
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::unique_ptr< llvm::MemoryBuffer > openInputFile(llvm::StringRef inputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for reading.
const FrozenRewritePatternSet GreedyRewriteConfig config
int JitRunnerMain(int argc, char **argv, const DialectRegistry ®istry, JitRunnerConfig config={})
Entry point for all CPU runners.
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 ...
OwningOpRef< Operation * > parseSourceFileForTool(const std::shared_ptr< llvm::SourceMgr > &sourceMgr, const ParserConfig &config, bool insertImplicitModule)
This parses the file specified by the indicated SourceMgr.
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...
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.
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.
JitRunner command line options used by JitRunnerConfig methods.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.