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 engine->initialize();
207 auto expectedFPtr = engine->lookupPacked(entryPoint);
209 return expectedFPtr.takeError();
212 engine->dumpToObjectFile(
options.objectFilename.empty()
216 void (*fptr)(
void **) = *expectedFPtr;
219 return Error::success();
224 CompileAndExecuteConfig
config, std::unique_ptr<llvm::TargetMachine> tm) {
225 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
227 if (!mainFunction || mainFunction.isExternal())
230 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
231 .getNumParams() != 0)
233 "JIT can't invoke a main function expecting arguments");
235 auto resultType = dyn_cast<LLVM::LLVMVoidType>(
236 mainFunction.getFunctionType().getReturnType());
240 void *empty =
nullptr;
242 &empty, std::move(tm));
245 template <
typename Type>
249 auto resultType = dyn_cast<IntegerType>(
250 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
252 if (!resultType || resultType.getWidth() != 32)
254 return Error::success();
258 auto resultType = dyn_cast<IntegerType>(
259 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
261 if (!resultType || resultType.getWidth() != 64)
263 return Error::success();
267 if (!isa<Float32Type>(
268 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
271 return Error::success();
273 template <
typename Type>
276 CompileAndExecuteConfig
config, std::unique_ptr<llvm::TargetMachine> tm) {
277 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
279 if (!mainFunction || mainFunction.isExternal())
282 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
283 .getNumParams() != 0)
285 "JIT can't invoke a main function expecting arguments");
287 if (
Error error = checkCompatibleReturnType<Type>(mainFunction))
297 (
void **)&data, std::move(tm)))
301 llvm::outs() << res <<
'\n';
303 return Error::success();
310 llvm::ExitOnError exitOnErr;
315 llvm::cl::ParseCommandLineOptions(argc, argv,
"MLIR CPU execution driver\n");
318 auto j = llvm::orc::LLJITBuilder().create();
320 llvm::outs() <<
"true\n";
322 llvm::outs() <<
"false\n";
323 exitOnErr(
j.takeError());
337 llvm::errs() <<
"could not parse the input IR\n";
342 if (
config.mlirTransformer)
343 if (
failed(
config.mlirTransformer(m.get(), runnerOptions)))
346 auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
347 if (!tmBuilderOrError) {
348 llvm::errs() <<
"Failed to create a JITTargetMachineBuilder for the host\n";
353 llvm::SubtargetFeatures features;
355 for (StringRef attr :
options.mAttrs)
356 features.AddFeature(attr);
357 tmBuilderOrError->addFeatures(features.getFeatures());
361 tmBuilderOrError->getTargetTriple().setArchName(
options.mArch);
365 auto tmOrError = tmBuilderOrError->createTargetMachine();
368 llvm::errs() <<
"Failed to create a TargetMachine for the host\n";
369 exitOnErr(tmOrError.takeError());
373 llvm::dbgs() <<
" JITTargetMachineBuilder is "
374 << llvm::orc::JITTargetMachineBuilderPrinter(*tmBuilderOrError,
378 CompileAndExecuteConfig compileAndExecuteConfig;
381 *optLevel, 0, tmOrError->get());
383 compileAndExecuteConfig.llvmModuleBuilder =
config.llvmModuleBuilder;
384 compileAndExecuteConfig.runtimeSymbolMap =
config.runtimesymbolMap;
387 using CompileAndExecuteFnT =
388 Error (*)(Options &,
Operation *, StringRef, CompileAndExecuteConfig,
389 std::unique_ptr<llvm::TargetMachine> tm);
390 auto compileAndExecuteFn =
392 .Case(
"i32", compileAndExecuteSingleReturnFunction<int32_t>)
393 .Case(
"i64", compileAndExecuteSingleReturnFunction<int64_t>)
394 .Case(
"f32", compileAndExecuteSingleReturnFunction<float>)
398 Error error = compileAndExecuteFn
399 ? compileAndExecuteFn(
401 compileAndExecuteConfig, std::move(tmOrError.get()))
404 int exitCode = EXIT_SUCCESS;
405 llvm::handleAllErrors(std::move(error),
406 [&exitCode](
const llvm::ErrorInfoBase &info) {
407 llvm::errs() <<
"Error: ";
408 info.log(llvm::errs());
409 llvm::errs() <<
'\n';
410 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.