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.empty())
228 auto resultType = dyn_cast<LLVM::LLVMVoidType>(
229 mainFunction.getFunctionType().getReturnType());
233 void *empty =
nullptr;
235 &empty, std::move(tm));
238 template <
typename Type>
242 auto resultType = dyn_cast<IntegerType>(
243 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
245 if (!resultType || resultType.getWidth() != 32)
247 return Error::success();
251 auto resultType = dyn_cast<IntegerType>(
252 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
254 if (!resultType || resultType.getWidth() != 64)
256 return Error::success();
260 if (!isa<Float32Type>(
261 cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
264 return Error::success();
266 template <
typename Type>
269 CompileAndExecuteConfig
config, std::unique_ptr<llvm::TargetMachine> tm) {
270 auto mainFunction = dyn_cast_or_null<LLVM::LLVMFuncOp>(
272 if (!mainFunction || mainFunction.isExternal())
275 if (cast<LLVM::LLVMFunctionType>(mainFunction.getFunctionType())
276 .getNumParams() != 0)
279 if (
Error error = checkCompatibleReturnType<Type>(mainFunction))
289 (
void **)&data, std::move(tm)))
293 llvm::outs() << res <<
'\n';
295 return Error::success();
302 llvm::ExitOnError exitOnErr;
307 llvm::cl::ParseCommandLineOptions(argc, argv,
"MLIR CPU execution driver\n");
310 auto j = llvm::orc::LLJITBuilder().create();
312 llvm::outs() <<
"true\n";
314 llvm::outs() <<
"false\n";
315 exitOnErr(
j.takeError());
329 llvm::errs() <<
"could not parse the input IR\n";
334 if (
config.mlirTransformer)
335 if (failed(
config.mlirTransformer(m.get(), runnerOptions)))
338 auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
339 if (!tmBuilderOrError) {
340 llvm::errs() <<
"Failed to create a JITTargetMachineBuilder for the host\n";
345 llvm::SubtargetFeatures features;
347 for (StringRef attr :
options.mAttrs)
348 features.AddFeature(attr);
349 tmBuilderOrError->addFeatures(features.getFeatures());
353 tmBuilderOrError->getTargetTriple().setArchName(
options.mArch);
357 auto tmOrError = tmBuilderOrError->createTargetMachine();
360 llvm::errs() <<
"Failed to create a TargetMachine for the host\n";
361 exitOnErr(tmOrError.takeError());
365 llvm::dbgs() <<
" JITTargetMachineBuilder is "
366 << llvm::orc::JITTargetMachineBuilderPrinter(*tmBuilderOrError,
370 CompileAndExecuteConfig compileAndExecuteConfig;
373 *optLevel, 0, tmOrError->get());
375 compileAndExecuteConfig.llvmModuleBuilder =
config.llvmModuleBuilder;
376 compileAndExecuteConfig.runtimeSymbolMap =
config.runtimesymbolMap;
379 using CompileAndExecuteFnT =
380 Error (*)(Options &,
Operation *, StringRef, CompileAndExecuteConfig,
381 std::unique_ptr<llvm::TargetMachine> tm);
382 auto compileAndExecuteFn =
384 .Case(
"i32", compileAndExecuteSingleReturnFunction<int32_t>)
385 .Case(
"i64", compileAndExecuteSingleReturnFunction<int64_t>)
386 .Case(
"f32", compileAndExecuteSingleReturnFunction<float>)
390 Error error = compileAndExecuteFn
391 ? compileAndExecuteFn(
393 compileAndExecuteConfig, std::move(tmOrError.get()))
396 int exitCode = EXIT_SUCCESS;
397 llvm::handleAllErrors(std::move(error),
398 [&exitCode](
const llvm::ErrorInfoBase &info) {
399 llvm::errs() <<
"Error: ";
400 info.log(llvm::errs());
401 llvm::errs() <<
'\n';
402 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.