Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
//===- ExecutionEngine.cpp - MLIR Execution engine and utils --------------===//
|
|
|
|
//
|
2020-01-26 11:58:30 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2019-12-24 01:35:36 +08:00
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
//
|
|
|
|
// This file implements the execution engine for MLIR modules based on LLVM Orc
|
|
|
|
// JIT engine.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/ExecutionEngine/ExecutionEngine.h"
|
2020-04-16 19:14:43 +08:00
|
|
|
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
#include "mlir/IR/Function.h"
|
|
|
|
#include "mlir/IR/Module.h"
|
2019-08-31 04:01:34 +08:00
|
|
|
#include "mlir/Support/FileUtilities.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
#include "mlir/Target/LLVMIR.h"
|
|
|
|
|
2020-02-05 09:28:25 +08:00
|
|
|
#include "llvm/ExecutionEngine/JITEventListener.h"
|
2019-08-22 09:15:39 +08:00
|
|
|
#include "llvm/ExecutionEngine/ObjectCache.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
|
|
|
|
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
|
|
|
|
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
2019-02-08 00:12:14 +08:00
|
|
|
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
|
|
|
|
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
|
|
|
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2020-05-20 11:29:16 +08:00
|
|
|
#include "llvm/MC/SubtargetFeature.h"
|
2019-09-07 23:53:24 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
#include "llvm/Support/Error.h"
|
2020-03-12 07:37:46 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2019-08-31 04:01:34 +08:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
|
2019-09-07 23:53:24 +08:00
|
|
|
#define DEBUG_TYPE "execution-engine"
|
|
|
|
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
using namespace mlir;
|
2019-08-22 09:15:39 +08:00
|
|
|
using llvm::dbgs;
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
using llvm::Error;
|
2019-08-22 09:15:39 +08:00
|
|
|
using llvm::errs;
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
using llvm::Expected;
|
2019-08-22 09:15:39 +08:00
|
|
|
using llvm::LLVMContext;
|
|
|
|
using llvm::MemoryBuffer;
|
|
|
|
using llvm::MemoryBufferRef;
|
|
|
|
using llvm::Module;
|
|
|
|
using llvm::SectionMemoryManager;
|
|
|
|
using llvm::StringError;
|
|
|
|
using llvm::Triple;
|
|
|
|
using llvm::orc::DynamicLibrarySearchGenerator;
|
|
|
|
using llvm::orc::ExecutionSession;
|
|
|
|
using llvm::orc::IRCompileLayer;
|
|
|
|
using llvm::orc::JITTargetMachineBuilder;
|
2020-05-15 04:29:53 +08:00
|
|
|
using llvm::orc::MangleAndInterner;
|
2019-08-22 09:15:39 +08:00
|
|
|
using llvm::orc::RTDyldObjectLinkingLayer;
|
2020-05-15 04:29:53 +08:00
|
|
|
using llvm::orc::SymbolMap;
|
2019-08-22 09:15:39 +08:00
|
|
|
using llvm::orc::ThreadSafeModule;
|
|
|
|
using llvm::orc::TMOwningSimpleCompiler;
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
|
2019-12-19 02:46:16 +08:00
|
|
|
/// Wrap a string into an llvm::StringError.
|
|
|
|
static Error make_string_error(const Twine &message) {
|
2019-08-22 09:15:39 +08:00
|
|
|
return llvm::make_error<StringError>(message.str(),
|
|
|
|
llvm::inconvertibleErrorCode());
|
|
|
|
}
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
|
2019-08-22 09:15:39 +08:00
|
|
|
void SimpleObjectCache::notifyObjectCompiled(const Module *M,
|
|
|
|
MemoryBufferRef ObjBuffer) {
|
2019-08-31 04:01:34 +08:00
|
|
|
cachedObjects[M->getModuleIdentifier()] = MemoryBuffer::getMemBufferCopy(
|
2019-08-22 09:15:39 +08:00
|
|
|
ObjBuffer.getBuffer(), ObjBuffer.getBufferIdentifier());
|
2019-05-16 00:26:27 +08:00
|
|
|
}
|
|
|
|
|
2019-08-22 09:15:39 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> SimpleObjectCache::getObject(const Module *M) {
|
2019-08-31 04:01:34 +08:00
|
|
|
auto I = cachedObjects.find(M->getModuleIdentifier());
|
|
|
|
if (I == cachedObjects.end()) {
|
2019-09-07 23:53:24 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "No object for " << M->getModuleIdentifier()
|
|
|
|
<< " in cache. Compiling.\n");
|
2019-08-22 09:15:39 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2019-09-07 23:53:24 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Object for " << M->getModuleIdentifier()
|
|
|
|
<< " loaded from cache.\n");
|
2019-08-22 09:15:39 +08:00
|
|
|
return MemoryBuffer::getMemBuffer(I->second->getMemBufferRef());
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
}
|
|
|
|
|
2019-12-19 01:28:48 +08:00
|
|
|
void SimpleObjectCache::dumpToObjectFile(StringRef outputFilename) {
|
2019-08-31 04:01:34 +08:00
|
|
|
// Set up the output file.
|
|
|
|
std::string errorMessage;
|
|
|
|
auto file = openOutputFile(outputFilename, &errorMessage);
|
|
|
|
if (!file) {
|
|
|
|
llvm::errs() << errorMessage << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dump the object generated for a single module to the output file.
|
|
|
|
assert(cachedObjects.size() == 1 && "Expected only one object entry.");
|
|
|
|
auto &cachedObject = cachedObjects.begin()->second;
|
|
|
|
file->os() << cachedObject->getBuffer();
|
|
|
|
file->keep();
|
|
|
|
}
|
|
|
|
|
2019-12-19 01:28:48 +08:00
|
|
|
void ExecutionEngine::dumpToObjectFile(StringRef filename) {
|
2019-08-31 04:01:34 +08:00
|
|
|
cache->dumpToObjectFile(filename);
|
|
|
|
}
|
|
|
|
|
2020-05-15 04:29:53 +08:00
|
|
|
void ExecutionEngine::registerSymbols(
|
|
|
|
llvm::function_ref<SymbolMap(MangleAndInterner)> symbolMap) {
|
|
|
|
auto &mainJitDylib = jit->getMainJITDylib();
|
|
|
|
cantFail(mainJitDylib.define(
|
|
|
|
absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner(
|
|
|
|
mainJitDylib.getExecutionSession(), jit->getDataLayout())))));
|
|
|
|
}
|
|
|
|
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
// Setup LLVM target triple from the current machine.
|
2019-08-22 09:15:39 +08:00
|
|
|
bool ExecutionEngine::setupTargetTriple(Module *llvmModule) {
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
// Setup the machine properties from the current architecture.
|
|
|
|
auto targetTriple = llvm::sys::getDefaultTargetTriple();
|
|
|
|
std::string errorMessage;
|
|
|
|
auto target = llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
|
|
|
|
if (!target) {
|
2019-08-22 09:15:39 +08:00
|
|
|
errs() << "NO target: " << errorMessage << "\n";
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
2020-05-20 11:29:16 +08:00
|
|
|
|
|
|
|
std::string cpu(llvm::sys::getHostCPUName());
|
|
|
|
llvm::SubtargetFeatures features;
|
|
|
|
llvm::StringMap<bool> hostFeatures;
|
|
|
|
|
|
|
|
if (llvm::sys::getHostCPUFeatures(hostFeatures))
|
|
|
|
for (auto &f : hostFeatures)
|
|
|
|
features.AddFeature(f.first(), f.second);
|
|
|
|
|
|
|
|
std::unique_ptr<llvm::TargetMachine> machine(target->createTargetMachine(
|
|
|
|
targetTriple, cpu, features.getString(), {}, {}));
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
llvmModule->setDataLayout(machine->createDataLayout());
|
|
|
|
llvmModule->setTargetTriple(targetTriple);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string makePackedFunctionName(StringRef name) {
|
|
|
|
return "_mlir_" + name.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// For each function in the LLVM module, define an interface function that wraps
|
|
|
|
// all the arguments of the original function and all its results into an i8**
|
|
|
|
// pointer to provide a unified invocation interface.
|
2020-01-14 21:06:12 +08:00
|
|
|
static void packFunctionArguments(Module *module) {
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
auto &ctx = module->getContext();
|
|
|
|
llvm::IRBuilder<> builder(ctx);
|
2019-12-19 01:28:48 +08:00
|
|
|
DenseSet<llvm::Function *> interfaceFunctions;
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
for (auto &func : module->getFunctionList()) {
|
|
|
|
if (func.isDeclaration()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (interfaceFunctions.count(&func)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given a function `foo(<...>)`, define the interface function
|
|
|
|
// `mlir_foo(i8**)`.
|
|
|
|
auto newType = llvm::FunctionType::get(
|
|
|
|
builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(),
|
|
|
|
/*isVarArg=*/false);
|
|
|
|
auto newName = makePackedFunctionName(func.getName());
|
2019-02-02 03:04:48 +08:00
|
|
|
auto funcCst = module->getOrInsertFunction(newName, newType);
|
2019-12-19 01:28:48 +08:00
|
|
|
llvm::Function *interfaceFunc = cast<llvm::Function>(funcCst.getCallee());
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
interfaceFunctions.insert(interfaceFunc);
|
|
|
|
|
|
|
|
// Extract the arguments from the type-erased argument list and cast them to
|
|
|
|
// the proper types.
|
|
|
|
auto bb = llvm::BasicBlock::Create(ctx);
|
|
|
|
bb->insertInto(interfaceFunc);
|
|
|
|
builder.SetInsertPoint(bb);
|
|
|
|
llvm::Value *argList = interfaceFunc->arg_begin();
|
2019-12-19 01:28:48 +08:00
|
|
|
SmallVector<llvm::Value *, 8> args;
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
args.reserve(llvm::size(func.args()));
|
|
|
|
for (auto &indexedArg : llvm::enumerate(func.args())) {
|
|
|
|
llvm::Value *argIndex = llvm::Constant::getIntegerValue(
|
2019-12-19 01:28:48 +08:00
|
|
|
builder.getInt64Ty(), APInt(64, indexedArg.index()));
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
llvm::Value *argPtrPtr = builder.CreateGEP(argList, argIndex);
|
|
|
|
llvm::Value *argPtr = builder.CreateLoad(argPtrPtr);
|
|
|
|
argPtr = builder.CreateBitCast(
|
|
|
|
argPtr, indexedArg.value().getType()->getPointerTo());
|
|
|
|
llvm::Value *arg = builder.CreateLoad(argPtr);
|
|
|
|
args.push_back(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call the implementation function with the extracted arguments.
|
|
|
|
llvm::Value *result = builder.CreateCall(&func, args);
|
|
|
|
|
|
|
|
// Assuming the result is one value, potentially of type `void`.
|
|
|
|
if (!result->getType()->isVoidTy()) {
|
|
|
|
llvm::Value *retIndex = llvm::Constant::getIntegerValue(
|
2019-12-19 01:28:48 +08:00
|
|
|
builder.getInt64Ty(), APInt(64, llvm::size(func.args())));
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
llvm::Value *retPtrPtr = builder.CreateGEP(argList, retIndex);
|
|
|
|
llvm::Value *retPtr = builder.CreateLoad(retPtrPtr);
|
|
|
|
retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo());
|
|
|
|
builder.CreateStore(result, retPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The interface function returns void.
|
|
|
|
builder.CreateRetVoid();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[mlir] [ExecutionEngine] add option to enable/disable GDB notification listener
Summary:
This way, clients can opt-out of the GDB notification listener. Also, this
changes the semantics of enabling the object cache, which seemed the wrong
way around.
Reviewers: rriddle, nicolasvasilache, ftynse, andydavis1
Reviewed By: nicolasvasilache
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D75787
2020-03-07 09:01:18 +08:00
|
|
|
ExecutionEngine::ExecutionEngine(bool enableObjectCache,
|
2020-05-09 17:13:50 +08:00
|
|
|
bool enableGDBNotificationListener,
|
|
|
|
bool enablePerfNotificationListener)
|
[mlir] [ExecutionEngine] add option to enable/disable GDB notification listener
Summary:
This way, clients can opt-out of the GDB notification listener. Also, this
changes the semantics of enabling the object cache, which seemed the wrong
way around.
Reviewers: rriddle, nicolasvasilache, ftynse, andydavis1
Reviewed By: nicolasvasilache
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D75787
2020-03-07 09:01:18 +08:00
|
|
|
: cache(enableObjectCache ? new SimpleObjectCache() : nullptr),
|
|
|
|
gdbListener(enableGDBNotificationListener
|
|
|
|
? llvm::JITEventListener::createGDBRegistrationListener()
|
2020-05-09 17:13:50 +08:00
|
|
|
: nullptr),
|
|
|
|
perfListener(enablePerfNotificationListener
|
|
|
|
? llvm::JITEventListener::createPerfJITEventListener()
|
|
|
|
: nullptr) {}
|
2019-08-31 04:01:34 +08:00
|
|
|
|
|
|
|
Expected<std::unique_ptr<ExecutionEngine>> ExecutionEngine::create(
|
2020-05-15 04:29:53 +08:00
|
|
|
ModuleOp m, llvm::function_ref<Error(llvm::Module *)> transformer,
|
2019-09-08 00:59:47 +08:00
|
|
|
Optional<llvm::CodeGenOpt::Level> jitCodeGenOptLevel,
|
[mlir] [ExecutionEngine] add option to enable/disable GDB notification listener
Summary:
This way, clients can opt-out of the GDB notification listener. Also, this
changes the semantics of enabling the object cache, which seemed the wrong
way around.
Reviewers: rriddle, nicolasvasilache, ftynse, andydavis1
Reviewed By: nicolasvasilache
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D75787
2020-03-07 09:01:18 +08:00
|
|
|
ArrayRef<StringRef> sharedLibPaths, bool enableObjectCache,
|
2020-05-09 17:13:50 +08:00
|
|
|
bool enableGDBNotificationListener, bool enablePerfNotificationListener) {
|
[mlir] [ExecutionEngine] add option to enable/disable GDB notification listener
Summary:
This way, clients can opt-out of the GDB notification listener. Also, this
changes the semantics of enabling the object cache, which seemed the wrong
way around.
Reviewers: rriddle, nicolasvasilache, ftynse, andydavis1
Reviewed By: nicolasvasilache
Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D75787
2020-03-07 09:01:18 +08:00
|
|
|
auto engine = std::make_unique<ExecutionEngine>(
|
2020-05-09 17:13:50 +08:00
|
|
|
enableObjectCache, enableGDBNotificationListener,
|
|
|
|
enablePerfNotificationListener);
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
|
2019-08-22 09:15:39 +08:00
|
|
|
std::unique_ptr<llvm::LLVMContext> ctx(new llvm::LLVMContext);
|
2019-07-03 01:49:17 +08:00
|
|
|
auto llvmModule = translateModuleToLLVMIR(m);
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
if (!llvmModule)
|
|
|
|
return make_string_error("could not convert to LLVM IR");
|
|
|
|
// FIXME: the triple should be passed to the translation or dialect conversion
|
|
|
|
// instead of this. Currently, the LLVM module created above has no triple
|
|
|
|
// associated with it.
|
|
|
|
setupTargetTriple(llvmModule.get());
|
|
|
|
packFunctionArguments(llvmModule.get());
|
|
|
|
|
2019-08-22 09:15:39 +08:00
|
|
|
// Clone module in a new LLVMContext since translateModuleToLLVMIR buries
|
|
|
|
// ownership too deeply.
|
|
|
|
// TODO(zinenko): Reevaluate model of ownership of LLVMContext in LLVMDialect.
|
2020-04-16 19:14:43 +08:00
|
|
|
std::unique_ptr<Module> deserModule =
|
|
|
|
LLVM::cloneModuleIntoNewContext(ctx.get(), llvmModule.get());
|
2020-02-21 06:16:20 +08:00
|
|
|
auto dataLayout = deserModule->getDataLayout();
|
2019-08-22 09:15:39 +08:00
|
|
|
|
|
|
|
// Callback to create the object layer with symbol resolution to current
|
|
|
|
// process and dynamically linked libraries.
|
|
|
|
auto objectLinkingLayerCreator = [&](ExecutionSession &session,
|
|
|
|
const Triple &TT) {
|
|
|
|
auto objectLayer = std::make_unique<RTDyldObjectLinkingLayer>(
|
|
|
|
session, []() { return std::make_unique<SectionMemoryManager>(); });
|
2020-05-09 17:13:50 +08:00
|
|
|
|
|
|
|
// Register JIT event listeners if they are enabled.
|
|
|
|
if (engine->gdbListener)
|
|
|
|
objectLayer->registerJITEventListener(*engine->gdbListener);
|
|
|
|
if (engine->perfListener)
|
|
|
|
objectLayer->registerJITEventListener(*engine->perfListener);
|
2019-08-22 09:15:39 +08:00
|
|
|
|
|
|
|
// Resolve symbols from shared libraries.
|
|
|
|
for (auto libPath : sharedLibPaths) {
|
|
|
|
auto mb = llvm::MemoryBuffer::getFile(libPath);
|
|
|
|
if (!mb) {
|
|
|
|
errs() << "Fail to create MemoryBuffer for: " << libPath << "\n";
|
|
|
|
continue;
|
|
|
|
}
|
2020-02-20 08:46:16 +08:00
|
|
|
auto &JD = session.createBareJITDylib(std::string(libPath));
|
2019-08-22 09:15:39 +08:00
|
|
|
auto loaded = DynamicLibrarySearchGenerator::Load(
|
|
|
|
libPath.data(), dataLayout.getGlobalPrefix());
|
|
|
|
if (!loaded) {
|
2019-10-28 19:24:43 +08:00
|
|
|
errs() << "Could not load " << libPath << ":\n " << loaded.takeError()
|
|
|
|
<< "\n";
|
2019-08-22 09:15:39 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
JD.addGenerator(std::move(*loaded));
|
|
|
|
cantFail(objectLayer->add(JD, std::move(mb.get())));
|
|
|
|
}
|
|
|
|
|
|
|
|
return objectLayer;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Callback to inspect the cache and recompile on demand. This follows Lang's
|
|
|
|
// LLJITWithObjectCache example.
|
|
|
|
auto compileFunctionCreator = [&](JITTargetMachineBuilder JTMB)
|
2020-01-22 17:12:04 +08:00
|
|
|
-> Expected<std::unique_ptr<IRCompileLayer::IRCompiler>> {
|
2019-09-08 00:59:47 +08:00
|
|
|
if (jitCodeGenOptLevel)
|
|
|
|
JTMB.setCodeGenOptLevel(jitCodeGenOptLevel.getValue());
|
2019-08-22 09:15:39 +08:00
|
|
|
auto TM = JTMB.createTargetMachine();
|
|
|
|
if (!TM)
|
|
|
|
return TM.takeError();
|
2020-01-22 17:12:04 +08:00
|
|
|
return std::make_unique<TMOwningSimpleCompiler>(std::move(*TM),
|
|
|
|
engine->cache.get());
|
2019-08-22 09:15:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Create the LLJIT by calling the LLJITBuilder with 2 callbacks.
|
|
|
|
auto jit =
|
|
|
|
cantFail(llvm::orc::LLJITBuilder()
|
|
|
|
.setCompileFunctionCreator(compileFunctionCreator)
|
|
|
|
.setObjectLinkingLayerCreator(objectLinkingLayerCreator)
|
|
|
|
.create());
|
|
|
|
|
|
|
|
// Add a ThreadSafemodule to the engine and return.
|
|
|
|
ThreadSafeModule tsm(std::move(deserModule), std::move(ctx));
|
Use transform function on llvm::Module in the ExecutionEngine
The refactoring of ExecutionEngine dropped the usage of the irTransform function used to pass -O3 and other options to LLVM. As a consequence, the proper optimizations do not kick in in LLMV-land.
This CL makes use of the transform function and allows producing avx512 instructions, on an internal example, when using:
`mlir-cpu-runner -dump-object-file=1 -object-filename=foo.o` combined with `objdump -D foo.o`.
Assembly produced resembles:
```
2b2e: 62 72 7d 48 18 04 0e vbroadcastss (%rsi,%rcx,1),%zmm8
2b35: 62 71 7c 48 28 ce vmovaps %zmm6,%zmm9
2b3b: 62 72 3d 48 a8 c9 vfmadd213ps %zmm1,%zmm8,%zmm9
2b41: 62 f1 7c 48 28 cf vmovaps %zmm7,%zmm1
2b47: 62 f2 3d 48 a8 c8 vfmadd213ps %zmm0,%zmm8,%zmm1
2b4d: 62 f2 7d 48 18 44 0e vbroadcastss 0x4(%rsi,%rcx,1),%zmm0
2b54: 01
2b55: 62 71 7c 48 28 c6 vmovaps %zmm6,%zmm8
2b5b: 62 72 7d 48 a8 c3 vfmadd213ps %zmm3,%zmm0,%zmm8
2b61: 62 f1 7c 48 28 df vmovaps %zmm7,%zmm3
2b67: 62 f2 7d 48 a8 da vfmadd213ps %zmm2,%zmm0,%zmm3
2b6d: 62 f2 7d 48 18 44 0e vbroadcastss 0x8(%rsi,%rcx,1),%zmm0
2b74: 02
2b75: 62 f2 7d 48 a8 f5 vfmadd213ps %zmm5,%zmm0,%zmm6
2b7b: 62 f2 7d 48 a8 fc vfmadd213ps %zmm4,%zmm0,%zmm7
```
etc.
Fixes tensorflow/mlir#120
PiperOrigin-RevId: 267281097
2019-09-05 10:16:32 +08:00
|
|
|
if (transformer)
|
|
|
|
cantFail(tsm.withModuleDo(
|
|
|
|
[&](llvm::Module &module) { return transformer(&module); }));
|
2019-08-22 09:15:39 +08:00
|
|
|
cantFail(jit->addIRModule(std::move(tsm)));
|
|
|
|
engine->jit = std::move(jit);
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
|
2020-02-21 06:16:20 +08:00
|
|
|
// Resolve symbols that are statically linked in the current process.
|
|
|
|
llvm::orc::JITDylib &mainJD = engine->jit->getMainJITDylib();
|
|
|
|
mainJD.addGenerator(
|
|
|
|
cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(
|
|
|
|
dataLayout.getGlobalPrefix())));
|
|
|
|
|
2019-03-29 09:00:57 +08:00
|
|
|
return std::move(engine);
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Expected<void (*)(void **)> ExecutionEngine::lookup(StringRef name) const {
|
|
|
|
auto expectedSymbol = jit->lookup(makePackedFunctionName(name));
|
2020-03-03 17:58:33 +08:00
|
|
|
|
|
|
|
// JIT lookup may return an Error referring to strings stored internally by
|
|
|
|
// the JIT. If the Error outlives the ExecutionEngine, it would want have a
|
|
|
|
// dangling reference, which is currently caught by an assertion inside JIT
|
|
|
|
// thanks to hand-rolled reference counting. Rewrap the error message into a
|
|
|
|
// string before returning. Alternatively, ORC JIT should consider copying
|
|
|
|
// the string into the error message.
|
|
|
|
if (!expectedSymbol) {
|
|
|
|
std::string errorMessage;
|
|
|
|
llvm::raw_string_ostream os(errorMessage);
|
|
|
|
llvm::handleAllErrors(expectedSymbol.takeError(),
|
|
|
|
[&os](llvm::ErrorInfoBase &ei) { ei.log(os); });
|
|
|
|
return make_string_error(os.str());
|
|
|
|
}
|
|
|
|
|
Simple CPU runner
This implements a simple CPU runner based on LLVM Orc JIT. The base
functionality is provided by the ExecutionEngine class that compiles and links
the module, and provides an interface for obtaining function pointers to the
JIT-compiled MLIR functions and for invoking those functions directly. Since
function pointers need to be casted to the correct pointer type, the
ExecutionEngine wraps LLVM IR functions obtained from MLIR into a helper
function with the common signature `void (void **)` where the single argument
is interpreted as a list of pointers to the actual arguments passed to the
function, eventually followed by a pointer to the result of the function.
Additionally, the ExecutionEngine is set up to resolve library functions to
those available in the current process, enabling support for, e.g., simple C
library calls.
For integration purposes, this also provides a simplistic runtime for memref
descriptors as expected by the LLVM IR code produced by MLIR translation. In
particular, memrefs are transformed into LLVM structs (can be mapped to C
structs) with a pointer to the data, followed by dynamic sizes. This
implementation only supports statically-shaped memrefs of type float, but can
be extened if necessary.
Provide a binary for the runner and a test that exercises it.
PiperOrigin-RevId: 230876363
2019-01-25 19:16:06 +08:00
|
|
|
auto rawFPtr = expectedSymbol->getAddress();
|
|
|
|
auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
|
|
|
|
if (!fptr)
|
|
|
|
return make_string_error("looked up function is null");
|
|
|
|
return fptr;
|
|
|
|
}
|
2019-01-26 06:57:30 +08:00
|
|
|
|
2019-08-22 09:15:39 +08:00
|
|
|
Error ExecutionEngine::invoke(StringRef name, MutableArrayRef<void *> args) {
|
2019-01-26 06:57:30 +08:00
|
|
|
auto expectedFPtr = lookup(name);
|
|
|
|
if (!expectedFPtr)
|
|
|
|
return expectedFPtr.takeError();
|
|
|
|
auto fptr = *expectedFPtr;
|
|
|
|
|
|
|
|
(*fptr)(args.data());
|
|
|
|
|
2019-08-22 09:15:39 +08:00
|
|
|
return Error::success();
|
2019-01-26 06:57:30 +08:00
|
|
|
}
|