Call llc, ld from within onnx-mlir. (#127)

* Call llc, ld from within onnx-mlir.

* Rename EmitLLVMBC -> EmitLib., reorder header files

* Edit comment.

Co-authored-by: Gheorghe-Teodor Bercea <gt.bercea@gmail.com>
This commit is contained in:
Tian Jin 2020-05-19 10:15:48 +08:00 committed by GitHub
parent 30a9070c8d
commit 4cdc0873ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 24 deletions

View File

@ -11,6 +11,18 @@ add_executable(onnx-mlir
MainUtils.cpp MainUtils.cpp
main.cpp) main.cpp)
# Locate llc, which is needed for translating LLVM bitcode
# to object file.
if(NOT EXISTS "${LLVM_PROJ_BUILD}/bin/llc")
message(ERROR "Cannot find llc.")
endif()
# Get the compiler command name, the C++ compiler is needed to to translate
# object files to shared libraries.
get_filename_component(CXX_COMPILER_FILENAME ${CMAKE_CXX_COMPILER} NAME)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ExternalUtil.hpp.in
${CMAKE_CURRENT_BINARY_DIR}/ExternalUtil.hpp)
set(ONNX_MLIR_LD_PRELOAD_onnx-mlir "" CACHE STRING "" FORCE) set(ONNX_MLIR_LD_PRELOAD_onnx-mlir "" CACHE STRING "" FORCE)
whole_archive_link_mlir(onnx-mlir ${MLIRWholeArchiveLibs}) whole_archive_link_mlir(onnx-mlir ${MLIRWholeArchiveLibs})
if(BUILD_SHARED_LIBS) if(BUILD_SHARED_LIBS)

9
src/ExternalUtil.hpp.in Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <string>
namespace onnx_mlir {
const std::string kLlcPath = "@LLVM_PROJ_BUILD@/bin/llc";
const std::string kCxxPath = "@CMAKE_CXX_COMPILER@";
const std::string kCxxFileName = "@CXX_COMPILER_FILENAME@";
const std::string kRuntimeDirPath = "@CMAKE_BINARY_DIR@/lib";
}

View File

@ -8,9 +8,13 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "src/MainUtils.hpp" #include <cstdio>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h>
#include "llvm/Support/Program.h"
#include "src/ExternalUtil.hpp"
#include "src/MainUtils.hpp"
#ifdef _WIN32 #ifdef _WIN32
#include <io.h> #include <io.h>
@ -43,14 +47,33 @@ void LoadMLIR(string inputFilename, mlir::MLIRContext &context,
} }
} }
void EmitLLVMBitCode( void compileModuleToSharedLibrary(
const mlir::OwningModuleRef &module, string outputFilename) { const mlir::OwningModuleRef &module, string outputBaseName) {
// Write LLVM bitcode.
string outputFilename = outputBaseName + ".bc";
error_code error; error_code error;
llvm::raw_fd_ostream moduleBitcodeStream( llvm::raw_fd_ostream moduleBitcodeStream(
outputFilename, error, llvm::sys::fs::F_None); outputFilename, error, llvm::sys::fs::F_None);
llvm::WriteBitcodeToFile( llvm::WriteBitcodeToFile(
*mlir::translateModuleToLLVMIR(*module), moduleBitcodeStream); *mlir::translateModuleToLLVMIR(*module), moduleBitcodeStream);
moduleBitcodeStream.flush(); moduleBitcodeStream.flush();
// Compile bitcode to object file.
std::vector<std::string> llcArgs = {
"llc", "-filetype=obj", "-relocation-model=pic", outputFilename};
auto llcArgStrRefs =
std::vector<llvm::StringRef>(llcArgs.begin(), llcArgs.end());
llvm::sys::ExecuteAndWait(kLlcPath, llvm::makeArrayRef(llcArgStrRefs));
// Link with runtime.
// TODO(tjingrant): link with runtime library in LLVM, and make the shared
// library more self-contained.
std::vector<std::string> cxxArgs = {kCxxFileName, "-shared", "-fPIC",
outputBaseName + ".o", "-o", outputBaseName + ".so",
"-L" + kRuntimeDirPath, "-lcruntime", "-Wl,-rpath," + kRuntimeDirPath};
auto argsArrayRefVector =
std::vector<llvm::StringRef>(cxxArgs.begin(), cxxArgs.end());
llvm::sys::ExecuteAndWait(kCxxPath, llvm::makeArrayRef(argsArrayRefVector));
} }
void registerDialects() { void registerDialects() {
@ -149,11 +172,10 @@ void emitOutputFiles(string outputBaseName, EmissionTargetType emissionTarget,
// outside the function code at the beginning of the file in which case the // outside the function code at the beginning of the file in which case the
// elision of these constants is not strictly required. Elision is also not // elision of these constants is not strictly required. Elision is also not
// necessary when emitting the .bc file. // necessary when emitting the .bc file.
if (emissionTarget == EmitLLVMBC) { if (emissionTarget == EmitLib) {
// Write LLVM bitcode to disk. // Write LLVM bitcode to disk, compile & link.
string outputFilename = outputBaseName + ".bc"; compileModuleToSharedLibrary(module, outputBaseName);
EmitLLVMBitCode(module, outputFilename); printf("Shared library %s.so has been compiled.", outputBaseName.c_str());
printf("LLVM bitcode written to %s\n", outputFilename.c_str());
} else { } else {
// Emit the version with all constants included. // Emit the version with all constants included.
outputCode(module, outputBaseName, ".onnx.mlir"); outputCode(module, outputBaseName, ".onnx.mlir");

View File

@ -42,14 +42,14 @@ enum EmissionTargetType {
EmitONNXIR, EmitONNXIR,
EmitMLIR, EmitMLIR,
EmitLLVMIR, EmitLLVMIR,
EmitLLVMBC, EmitLib,
}; };
void LoadMLIR(std::string inputFilename, mlir::MLIRContext &context, void LoadMLIR(std::string inputFilename, mlir::MLIRContext &context,
mlir::OwningModuleRef &module); mlir::OwningModuleRef &module);
void EmitLLVMBitCode( void compileModuleToSharedLibrary(
const mlir::OwningModuleRef &module, std::string outputFilename); const mlir::OwningModuleRef &module, std::string outputBaseName);
void registerDialects(); void registerDialects();

View File

@ -31,9 +31,10 @@ int main(int argc, char *argv[]) {
clEnumVal( clEnumVal(
EmitMLIR, "Lower model to MLIR built-in transformation dialect."), EmitMLIR, "Lower model to MLIR built-in transformation dialect."),
clEnumVal(EmitLLVMIR, "Lower model to LLVM IR (LLVM dialect)."), clEnumVal(EmitLLVMIR, "Lower model to LLVM IR (LLVM dialect)."),
clEnumVal(EmitLLVMBC, "Lower model to LLVM IR and emit (to file) " clEnumVal(EmitLib, "Lower model to LLVM IR, emit (to file) "
"LLVM bitcode for model.")), "LLVM bitcode for model, compile and link it to a "
llvm::cl::init(EmitLLVMBC), llvm::cl::cat(OnnxMlirOptions)); "shared library.")),
llvm::cl::init(EmitLib), llvm::cl::cat(OnnxMlirOptions));
llvm::cl::HideUnrelatedOptions(OnnxMlirOptions); llvm::cl::HideUnrelatedOptions(OnnxMlirOptions);
llvm::cl::ParseCommandLineOptions( llvm::cl::ParseCommandLineOptions(

View File

@ -40,14 +40,6 @@ class DummyBackend(onnx.backend.base.Backend):
onnx.save(model, "temp_model.onnx") onnx.save(model, "temp_model.onnx")
# Call frontend to process temp_model.onnx, bit code will be generated. # Call frontend to process temp_model.onnx, bit code will be generated.
execute_commands([ONNX_MLIR, "temp_model.onnx"]) execute_commands([ONNX_MLIR, "temp_model.onnx"])
# Call llc to generate object file from bitcode.
execute_commands(
[LLC, "-filetype=obj", "-relocation-model=pic", "temp_model.bc"])
# Generate shared library from object file, linking with c runtime.
execute_commands([
CXX, "-shared", "-fPIC", "temp_model.o", "-o", "temp_model.so",
"-L" + RUNTIME_DIR, "-lcruntime", "-Wl,-rpath=" + RUNTIME_DIR,
])
return ExecutionSession("./temp_model.so", "_dyn_entry_point_main_graph") return ExecutionSession("./temp_model.so", "_dyn_entry_point_main_graph")
@classmethod @classmethod
@ -62,7 +54,6 @@ backend_test = onnx.backend.test.BackendTest(DummyBackend, __name__)
# Test directories: # Test directories:
# https://github.com/onnx/onnx/tree/master/onnx/backend/test/data/node # https://github.com/onnx/onnx/tree/master/onnx/backend/test/data/node
test_to_enable = [ test_to_enable = [
# Abs Op: # Abs Op:
"test_abs_cpu", "test_abs_cpu",