
Provide an option to specify optimization level when creating an ExecutionEngine via the MLIR JIT Python binding. Not only is the specified optimization level used for code generation, but all LLVM optimization passes at the optimization level are also run prior to machine code generation (akin to the mlir-cpu-runner tool). Default opt level continues to remain at level two (-O2). Contributions in part from Prashant Kumar <prashantk@polymagelabs.com> as well. Differential Revision: https://reviews.llvm.org/D102551
94 lines
3.4 KiB
C++
94 lines
3.4 KiB
C++
//===- ExecutionEngine.cpp - C API for MLIR JIT ---------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir-c/ExecutionEngine.h"
|
|
#include "mlir/CAPI/ExecutionEngine.h"
|
|
#include "mlir/CAPI/IR.h"
|
|
#include "mlir/CAPI/Support.h"
|
|
#include "mlir/ExecutionEngine/OptUtils.h"
|
|
#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
|
|
#include "llvm/ExecutionEngine/Orc/Mangling.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
|
|
using namespace mlir;
|
|
|
|
extern "C" MlirExecutionEngine mlirExecutionEngineCreate(MlirModule op,
|
|
int optLevel) {
|
|
static bool initOnce = [] {
|
|
llvm::InitializeNativeTarget();
|
|
llvm::InitializeNativeTargetAsmPrinter();
|
|
return true;
|
|
}();
|
|
(void)initOnce;
|
|
|
|
mlir::registerLLVMDialectTranslation(*unwrap(op)->getContext());
|
|
|
|
auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost();
|
|
if (!tmBuilderOrError) {
|
|
llvm::errs() << "Failed to create a JITTargetMachineBuilder for the host\n";
|
|
return MlirExecutionEngine{nullptr};
|
|
}
|
|
auto tmOrError = tmBuilderOrError->createTargetMachine();
|
|
if (!tmOrError) {
|
|
llvm::errs() << "Failed to create a TargetMachine for the host\n";
|
|
return MlirExecutionEngine{nullptr};
|
|
}
|
|
|
|
// Create a transformer to run all LLVM optimization passes at the
|
|
// specified optimization level.
|
|
auto llvmOptLevel = static_cast<llvm::CodeGenOpt::Level>(optLevel);
|
|
auto transformer = mlir::makeLLVMPassesTransformer(
|
|
/*passes=*/{}, llvmOptLevel, /*targetMachine=*/tmOrError->get());
|
|
auto jitOrError = ExecutionEngine::create(
|
|
unwrap(op), /*llvmModuleBuilder=*/{}, transformer, llvmOptLevel);
|
|
if (!jitOrError) {
|
|
consumeError(jitOrError.takeError());
|
|
return MlirExecutionEngine{nullptr};
|
|
}
|
|
return wrap(jitOrError->release());
|
|
}
|
|
|
|
extern "C" void mlirExecutionEngineDestroy(MlirExecutionEngine jit) {
|
|
delete (unwrap(jit));
|
|
}
|
|
|
|
extern "C" MlirLogicalResult
|
|
mlirExecutionEngineInvokePacked(MlirExecutionEngine jit, MlirStringRef name,
|
|
void **arguments) {
|
|
const std::string ifaceName = ("_mlir_ciface_" + unwrap(name)).str();
|
|
llvm::Error error = unwrap(jit)->invokePacked(
|
|
ifaceName, MutableArrayRef<void *>{arguments, (size_t)0});
|
|
if (error)
|
|
return wrap(failure());
|
|
return wrap(success());
|
|
}
|
|
|
|
extern "C" void *mlirExecutionEngineLookup(MlirExecutionEngine jit,
|
|
MlirStringRef name) {
|
|
auto expectedFPtr = unwrap(jit)->lookup(unwrap(name));
|
|
if (!expectedFPtr)
|
|
return nullptr;
|
|
return reinterpret_cast<void *>(*expectedFPtr);
|
|
}
|
|
|
|
extern "C" void mlirExecutionEngineRegisterSymbol(MlirExecutionEngine jit,
|
|
MlirStringRef name,
|
|
void *sym) {
|
|
unwrap(jit)->registerSymbols([&](llvm::orc::MangleAndInterner interner) {
|
|
llvm::orc::SymbolMap symbolMap;
|
|
symbolMap[interner(unwrap(name))] =
|
|
llvm::JITEvaluatedSymbol::fromPointer(sym);
|
|
return symbolMap;
|
|
});
|
|
}
|
|
|
|
extern "C" void mlirExecutionEngineDumpToObjectFile(MlirExecutionEngine jit,
|
|
MlirStringRef name) {
|
|
unwrap(jit)->dumpToObjectFile(unwrap(name));
|
|
}
|