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
|
|
|
//===- mlir-cpu-runner.cpp - MLIR CPU Execution Driver---------------------===//
|
|
|
|
//
|
|
|
|
// Copyright 2019 The MLIR Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
// =============================================================================
|
|
|
|
//
|
|
|
|
// This is a command line utility that executes an MLIR file on the CPU by
|
|
|
|
// translating MLIR to LLVM IR before JIT-compiling and executing the latter.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "mlir/ExecutionEngine/ExecutionEngine.h"
|
|
|
|
#include "mlir/ExecutionEngine/MemRefUtils.h"
|
2019-02-16 02:50:28 +08:00
|
|
|
#include "mlir/ExecutionEngine/OptUtils.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/MLIRContext.h"
|
|
|
|
#include "mlir/IR/Module.h"
|
|
|
|
#include "mlir/IR/StandardTypes.h"
|
2019-05-10 03:34:04 +08:00
|
|
|
#include "mlir/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/Parser.h"
|
|
|
|
#include "mlir/Support/FileUtilities.h"
|
|
|
|
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
2019-03-29 00:20:13 +08:00
|
|
|
#include "llvm/IR/LegacyPassNameParser.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/IR/Module.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/FileUtilities.h"
|
|
|
|
#include "llvm/Support/InitLLVM.h"
|
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2019-03-29 00:20:13 +08:00
|
|
|
#include "llvm/Support/StringSaver.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/TargetSelect.h"
|
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2019-03-28 01:38:23 +08:00
|
|
|
#include <numeric>
|
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;
|
|
|
|
using llvm::Error;
|
|
|
|
|
|
|
|
static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
|
|
|
|
llvm::cl::desc("<input file>"),
|
|
|
|
llvm::cl::init("-"));
|
|
|
|
static llvm::cl::opt<std::string>
|
|
|
|
initValue("init-value", llvm::cl::desc("Initial value of MemRef elements"),
|
|
|
|
llvm::cl::value_desc("<float value>"), llvm::cl::init("0.0"));
|
|
|
|
static llvm::cl::opt<std::string>
|
|
|
|
mainFuncName("e", llvm::cl::desc("The function to be called"),
|
|
|
|
llvm::cl::value_desc("<function name>"),
|
|
|
|
llvm::cl::init("main"));
|
2019-05-10 03:34:04 +08:00
|
|
|
static llvm::cl::opt<std::string> mainFuncType(
|
|
|
|
"entry-point-result",
|
|
|
|
llvm::cl::desc("Textual description of the function type to be called"),
|
|
|
|
llvm::cl::value_desc("f32 or memrefs"), llvm::cl::init("memrefs"));
|
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-03-29 00:20:13 +08:00
|
|
|
static llvm::cl::OptionCategory optFlags("opt-like flags");
|
|
|
|
|
|
|
|
// CLI list of pass information
|
|
|
|
static llvm::cl::list<const llvm::PassInfo *, bool, llvm::PassNameParser>
|
|
|
|
llvmPasses(llvm::cl::desc("LLVM optimizing passes to run"),
|
|
|
|
llvm::cl::cat(optFlags));
|
|
|
|
|
|
|
|
// CLI variables for -On options.
|
|
|
|
static llvm::cl::opt<bool> optO0("O0", llvm::cl::desc("Run opt O0 passes"),
|
|
|
|
llvm::cl::cat(optFlags));
|
|
|
|
static llvm::cl::opt<bool> optO1("O1", llvm::cl::desc("Run opt O1 passes"),
|
|
|
|
llvm::cl::cat(optFlags));
|
|
|
|
static llvm::cl::opt<bool> optO2("O2", llvm::cl::desc("Run opt O2 passes"),
|
|
|
|
llvm::cl::cat(optFlags));
|
|
|
|
static llvm::cl::opt<bool> optO3("O3", llvm::cl::desc("Run opt O3 passes"),
|
|
|
|
llvm::cl::cat(optFlags));
|
2019-02-16 02:50:28 +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
|
|
|
static std::unique_ptr<Module> parseMLIRInput(StringRef inputFilename,
|
|
|
|
MLIRContext *context) {
|
|
|
|
// Set up the input file.
|
|
|
|
std::string errorMessage;
|
|
|
|
auto file = openInputFile(inputFilename, &errorMessage);
|
|
|
|
if (!file) {
|
|
|
|
llvm::errs() << errorMessage << "\n";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::SourceMgr sourceMgr;
|
|
|
|
sourceMgr.AddNewSourceBuffer(std::move(file), llvm::SMLoc());
|
|
|
|
return std::unique_ptr<Module>(parseSourceFile(sourceMgr, context));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the relevant subsystems of LLVM.
|
|
|
|
static void initializeLLVM() {
|
|
|
|
llvm::InitializeNativeTarget();
|
|
|
|
llvm::InitializeNativeTargetAsmPrinter();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Error make_string_error(const llvm::Twine &message) {
|
|
|
|
return llvm::make_error<llvm::StringError>(message.str(),
|
|
|
|
llvm::inconvertibleErrorCode());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printOneMemRef(Type t, void *val) {
|
|
|
|
auto memRefType = t.cast<MemRefType>();
|
|
|
|
auto shape = memRefType.getShape();
|
|
|
|
int64_t size = std::accumulate(shape.begin(), shape.end(), 1,
|
|
|
|
std::multiplies<int64_t>());
|
|
|
|
for (int64_t i = 0; i < size; ++i) {
|
|
|
|
llvm::outs() << reinterpret_cast<StaticFloatMemRef *>(val)->data[i] << ' ';
|
|
|
|
}
|
|
|
|
llvm::outs() << '\n';
|
|
|
|
}
|
|
|
|
|
2019-02-14 07:30:24 +08:00
|
|
|
static void printMemRefArguments(ArrayRef<Type> argTypes,
|
|
|
|
ArrayRef<Type> resTypes,
|
|
|
|
ArrayRef<void *> args) {
|
|
|
|
auto properArgs = args.take_front(argTypes.size());
|
|
|
|
for (const auto &kvp : llvm::zip(argTypes, properArgs)) {
|
|
|
|
auto type = std::get<0>(kvp);
|
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 val = std::get<1>(kvp);
|
2019-02-14 07:30:24 +08:00
|
|
|
printOneMemRef(type, val);
|
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-02-14 07:30:24 +08:00
|
|
|
auto results = args.drop_front(argTypes.size());
|
|
|
|
for (const auto &kvp : llvm::zip(resTypes, results)) {
|
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 type = std::get<0>(kvp);
|
|
|
|
auto val = std::get<1>(kvp);
|
|
|
|
printOneMemRef(type, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-10 03:34:04 +08:00
|
|
|
static Error compileAndExecuteFunctionWithMemRefs(
|
|
|
|
Module *module, StringRef entryPoint,
|
|
|
|
std::function<llvm::Error(llvm::Module *)> transformer) {
|
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
|
|
|
Function *mainFunction = module->getNamedFunction(entryPoint);
|
|
|
|
if (!mainFunction || mainFunction->getBlocks().empty()) {
|
|
|
|
return make_string_error("entry point not found");
|
|
|
|
}
|
|
|
|
|
2019-02-14 07:30:24 +08:00
|
|
|
// Store argument and result types of the original function necessary to
|
|
|
|
// pretty print the results, because the function itself will be rewritten
|
|
|
|
// to use the LLVM dialect.
|
|
|
|
SmallVector<Type, 8> argTypes =
|
|
|
|
llvm::to_vector<8>(mainFunction->getType().getInputs());
|
|
|
|
SmallVector<Type, 8> resTypes =
|
|
|
|
llvm::to_vector<8>(mainFunction->getType().getResults());
|
|
|
|
|
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
|
|
|
float init = std::stof(initValue.getValue());
|
|
|
|
|
|
|
|
auto expectedArguments = allocateMemRefArguments(mainFunction, init);
|
|
|
|
if (!expectedArguments)
|
|
|
|
return expectedArguments.takeError();
|
|
|
|
|
2019-02-16 02:50:28 +08:00
|
|
|
auto expectedEngine = mlir::ExecutionEngine::create(module, transformer);
|
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 (!expectedEngine)
|
|
|
|
return expectedEngine.takeError();
|
|
|
|
|
|
|
|
auto engine = std::move(*expectedEngine);
|
|
|
|
auto expectedFPtr = engine->lookup(entryPoint);
|
|
|
|
if (!expectedFPtr)
|
|
|
|
return expectedFPtr.takeError();
|
|
|
|
void (*fptr)(void **) = *expectedFPtr;
|
|
|
|
(*fptr)(expectedArguments->data());
|
2019-02-14 07:30:24 +08:00
|
|
|
printMemRefArguments(argTypes, resTypes, *expectedArguments);
|
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
|
|
|
freeMemRefArguments(*expectedArguments);
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-05-10 03:34:04 +08:00
|
|
|
static Error compileAndExecuteSingleFloatReturnFunction(
|
|
|
|
Module *module, StringRef entryPoint,
|
|
|
|
std::function<llvm::Error(llvm::Module *)> transformer) {
|
|
|
|
Function *mainFunction = module->getNamedFunction(entryPoint);
|
|
|
|
if (!mainFunction || mainFunction->isExternal()) {
|
|
|
|
return make_string_error("entry point not found");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mainFunction->getType().getInputs().empty())
|
|
|
|
return make_string_error("function inputs not supported");
|
|
|
|
|
|
|
|
if (mainFunction->getType().getResults().size() != 1)
|
|
|
|
return make_string_error("only single f32 function result supported");
|
|
|
|
|
|
|
|
auto t = mainFunction->getType().getResults()[0].dyn_cast<LLVM::LLVMType>();
|
|
|
|
if (!t)
|
|
|
|
return make_string_error("only single llvm.f32 function result supported");
|
|
|
|
auto *llvmTy = t.getUnderlyingType();
|
|
|
|
if (llvmTy != llvmTy->getFloatTy(llvmTy->getContext()))
|
|
|
|
return make_string_error("only single llvm.f32 function result supported");
|
|
|
|
|
|
|
|
auto expectedEngine = mlir::ExecutionEngine::create(module, transformer);
|
|
|
|
if (!expectedEngine)
|
|
|
|
return expectedEngine.takeError();
|
|
|
|
|
|
|
|
auto engine = std::move(*expectedEngine);
|
|
|
|
auto expectedFPtr = engine->lookup(entryPoint);
|
|
|
|
if (!expectedFPtr)
|
|
|
|
return expectedFPtr.takeError();
|
|
|
|
void (*fptr)(void **) = *expectedFPtr;
|
|
|
|
|
|
|
|
float res;
|
|
|
|
struct {
|
|
|
|
void *data;
|
|
|
|
} data;
|
|
|
|
data.data = &res;
|
|
|
|
(*fptr)((void **)&data);
|
|
|
|
|
|
|
|
// Intentional printing of the output so we can test.
|
|
|
|
llvm::outs() << res;
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
int main(int argc, char **argv) {
|
|
|
|
llvm::PrettyStackTraceProgram x(argc, argv);
|
|
|
|
llvm::InitLLVM y(argc, argv);
|
|
|
|
|
|
|
|
initializeLLVM();
|
2019-02-16 02:50:28 +08:00
|
|
|
mlir::initializeLLVMPasses();
|
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-03-29 00:20:13 +08:00
|
|
|
llvm::SmallVector<std::reference_wrapper<llvm::cl::opt<bool>>, 4> optFlags{
|
|
|
|
optO0, optO1, optO2, optO3};
|
|
|
|
|
|
|
|
llvm::cl::ParseCommandLineOptions(argc, argv, "MLIR CPU execution driver\n");
|
|
|
|
|
|
|
|
llvm::SmallVector<const llvm::PassInfo *, 4> passes;
|
|
|
|
llvm::Optional<unsigned> optLevel;
|
|
|
|
unsigned optCLIPosition = 0;
|
|
|
|
// Determine if there is an optimization flag present, and its CLI position
|
|
|
|
// (optCLIPosition).
|
|
|
|
for (unsigned j = 0; j < 4; ++j) {
|
|
|
|
auto &flag = optFlags[j].get();
|
|
|
|
if (flag) {
|
|
|
|
optLevel = j;
|
|
|
|
optCLIPosition = flag.getPosition();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Generate vector of pass information, plus the index at which we should
|
|
|
|
// insert any optimization passes in that vector (optPosition).
|
|
|
|
unsigned optPosition = 0;
|
|
|
|
for (unsigned i = 0, e = llvmPasses.size(); i < e; ++i) {
|
|
|
|
passes.push_back(llvmPasses[i]);
|
|
|
|
if (optCLIPosition < llvmPasses.getPosition(i)) {
|
|
|
|
optPosition = i;
|
|
|
|
optCLIPosition = UINT_MAX; // To ensure we never insert again
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
MLIRContext context;
|
|
|
|
auto m = parseMLIRInput(inputFilename, &context);
|
|
|
|
if (!m) {
|
|
|
|
llvm::errs() << "could not parse the input IR\n";
|
|
|
|
return 1;
|
|
|
|
}
|
2019-02-16 02:50:28 +08:00
|
|
|
|
2019-03-29 00:20:13 +08:00
|
|
|
auto transformer =
|
|
|
|
mlir::makeLLVMPassesTransformer(passes, optLevel, optPosition);
|
2019-05-10 03:34:04 +08:00
|
|
|
auto error = mainFuncType.getValue() == "f32"
|
|
|
|
? compileAndExecuteSingleFloatReturnFunction(
|
|
|
|
m.get(), mainFuncName.getValue(), transformer)
|
|
|
|
: compileAndExecuteFunctionWithMemRefs(
|
|
|
|
m.get(), mainFuncName.getValue(), transformer);
|
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
|
|
|
int exitCode = EXIT_SUCCESS;
|
|
|
|
llvm::handleAllErrors(std::move(error),
|
|
|
|
[&exitCode](const llvm::ErrorInfoBase &info) {
|
|
|
|
llvm::errs() << "Error: ";
|
|
|
|
info.log(llvm::errs());
|
|
|
|
llvm::errs() << '\n';
|
|
|
|
exitCode = EXIT_FAILURE;
|
|
|
|
});
|
|
|
|
|
|
|
|
return exitCode;
|
|
|
|
}
|