LLVMAOTTarget compilation and linking
- Introduce FLAGS for target compilation.
- Compiles LLVMIR module into target object.
- Link target object using target toolchain binaries provided via IREE_LLVMAOT_LINKER_PATH environment variable to produce target dylib.
- If target IREE_LLVMAOT_LINKER_PATH isn't provided we call ELFLinker (Not implemented yet)
PiperOrigin-RevId: 319160133
diff --git a/bindings/python/build_defs.oss.bzl b/bindings/python/build_defs.oss.bzl
index d8cf789..7e51827 100644
--- a/bindings/python/build_defs.oss.bzl
+++ b/bindings/python/build_defs.oss.bzl
@@ -22,6 +22,7 @@
NUMPY_DEPS = []
PLATFORM_VULKAN_DEPS = _PLATFORM_VULKAN_DEPS
PYTHON_HEADERS_DEPS = ["@iree_native_python//:python_headers"]
+PYTHON_CPP_EXTRA_DEPS = []
PYBIND_COPTS = [
"-fexceptions",
diff --git a/bindings/python/pyiree/compiler/BUILD b/bindings/python/pyiree/compiler/BUILD
index a6560f9..3f4cf09 100644
--- a/bindings/python/pyiree/compiler/BUILD
+++ b/bindings/python/pyiree/compiler/BUILD
@@ -19,6 +19,7 @@
"PYBIND_EXTENSION_COPTS",
"PYBIND_FEATURES",
"PYBIND_REGISTER_MLIR_PASSES",
+ "PYTHON_CPP_EXTRA_DEPS",
"iree_py_extension",
"iree_py_library",
"iree_py_test",
@@ -54,7 +55,7 @@
"__init__.py",
],
srcs_version = "PY3",
- deps = [
+ deps = PYTHON_CPP_EXTRA_DEPS + [
":binding",
"//bindings/python:pathsetup", # build_cleaner: keep
],
@@ -89,6 +90,7 @@
"//iree/tools:init_compiler_modules",
"//iree/tools:init_iree_passes_and_dialects",
"//iree/tools:init_mlir_passes_and_dialects",
+ "//iree/base:localfile",
"//iree/tools:init_targets",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AllPassesAndDialectsNoRegistration",
diff --git a/bindings/python/pyiree/rt/BUILD b/bindings/python/pyiree/rt/BUILD
index fb00167..db48f43 100644
--- a/bindings/python/pyiree/rt/BUILD
+++ b/bindings/python/pyiree/rt/BUILD
@@ -82,6 +82,7 @@
deps = [
"//bindings/python/pyiree/common",
"//iree/base:api",
+ "//iree/base:localfile",
"//iree/base:signature_mangle",
"//iree/hal:api",
"//iree/modules/hal",
diff --git a/build_tools/bazel/build_bindings.sh b/build_tools/bazel/build_bindings.sh
index 56aef23..e79cade 100755
--- a/build_tools/bazel/build_bindings.sh
+++ b/build_tools/bazel/build_bindings.sh
@@ -39,9 +39,11 @@
if ! [[ -v IREE_VULKAN_DISABLE ]]; then
IREE_VULKAN_DISABLE=1
fi
+
declare -a test_env_args=(
--test_env=IREE_LLVMJIT_DISABLE=$IREE_LLVMJIT_DISABLE
--test_env=IREE_VULKAN_DISABLE=$IREE_VULKAN_DISABLE
+ --test_env=IREE_LLVMAOT_LINKER_PATH
)
declare -a default_build_tag_filters=("-nokokoro")
diff --git a/build_tools/cmake/iree_copts.cmake b/build_tools/cmake/iree_copts.cmake
index 542536b..63776ef 100644
--- a/build_tools/cmake/iree_copts.cmake
+++ b/build_tools/cmake/iree_copts.cmake
@@ -149,7 +149,8 @@
set(LLVM_ENABLE_IDE ON CACHE BOOL "" FORCE)
set(LLVM_ENABLE_RTTI ON CACHE BOOL "" FORCE)
-set(LLVM_TARGETS_TO_BUILD "WebAssembly;X86" CACHE STRING "" FORCE)
+# TODO(ataei): Use optional build time targets selection for LLVMAOT.
+set(LLVM_TARGETS_TO_BUILD "WebAssembly;X86;ARM;AArch64" CACHE STRING "" FORCE)
set(LLVM_ENABLE_PROJECTS "mlir" CACHE STRING "" FORCE)
set(LLVM_ENABLE_BINDINGS OFF CACHE BOOL "" FORCE)
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/BUILD b/iree/compiler/Dialect/HAL/Target/LLVM/BUILD
index ee7d12f..20d26ae 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/BUILD
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/BUILD
@@ -11,6 +11,8 @@
# 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.
+#
+load("//iree:build_defs.oss.bzl", "platform_trampoline_deps")
package(
default_visibility = ["//visibility:public"],
@@ -48,13 +50,20 @@
"LLVMAOTTarget.h",
],
deps = [
+ ":LLVMAOTTargetLinker",
":LLVMIRPasses",
":LLVMTargetOptions",
"//iree/compiler/Conversion/LinalgToLLVM",
"//iree/compiler/Dialect/HAL/Target",
"//iree/schemas:dylib_executable_def_cc_fbs",
+ "@llvm-project//llvm:AArch64AsmParser",
+ "@llvm-project//llvm:AArch64CodeGen",
+ "@llvm-project//llvm:ARMAsmParser",
+ "@llvm-project//llvm:ARMCodeGen",
"@llvm-project//llvm:Core",
"@llvm-project//llvm:Support",
+ "@llvm-project//llvm:X86AsmParser",
+ "@llvm-project//llvm:X86CodeGen",
"@llvm-project//mlir:TargetLLVMIR",
],
)
@@ -88,5 +97,23 @@
deps = [
"@llvm-project//llvm:Passes",
"@llvm-project//llvm:Support",
+ "@llvm-project//llvm:Target",
+ ],
+)
+
+cc_library(
+ name = "LLVMAOTTargetLinker",
+ hdrs = ["LLVMAOTTargetLinker.h"],
+ deps = [
+ "//iree/base:file_io",
+ ] + platform_trampoline_deps("LLVMAOTTargetLinker", "compiler/Dialect/HAL/Target/LLVM"),
+)
+
+cc_library(
+ name = "LLVMAOTTargetLinker_hdrs",
+ hdrs = ["LLVMAOTTargetLinker.h"],
+ deps = [
+ ":LLVMTargetOptions",
+ "//iree/base:file_io",
],
)
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/CMakeLists.txt b/iree/compiler/Dialect/HAL/Target/LLVM/CMakeLists.txt
index 3916453..4aa0ad3 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/CMakeLists.txt
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/CMakeLists.txt
@@ -42,10 +42,17 @@
SRCS
"LLVMAOTTarget.cpp"
DEPS
+ ::LLVMAOTTargetLinker
::LLVMIRPasses
::LLVMTargetOptions
+ LLVMAArch64AsmParser
+ LLVMAArch64CodeGen
+ LLVMARMAsmParser
+ LLVMARMCodeGen
LLVMCore
LLVMSupport
+ LLVMX86AsmParser
+ LLVMX86CodeGen
MLIRTargetLLVMIR
iree::compiler::Conversion::LinalgToLLVM
iree::compiler::Dialect::HAL::Target
@@ -80,5 +87,28 @@
DEPS
LLVMPasses
LLVMSupport
+ LLVMTarget
+ PUBLIC
+)
+
+iree_cc_library(
+ NAME
+ LLVMAOTTargetLinker
+ HDRS
+ "LLVMAOTTargetLinker.h"
+ DEPS
+ iree::base::file_io
+ iree::compiler::Dialect::HAL::Target::LLVM::internal::LLVMAOTTargetLinker_internal
+ PUBLIC
+)
+
+iree_cc_library(
+ NAME
+ LLVMAOTTargetLinker_hdrs
+ HDRS
+ "LLVMAOTTargetLinker.h"
+ DEPS
+ ::LLVMTargetOptions
+ iree::base::file_io
PUBLIC
)
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTarget.cpp b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTarget.cpp
index c2b8d9f..7269089 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTarget.cpp
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTarget.cpp
@@ -14,7 +14,10 @@
#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTarget.h"
+#include <cstdlib>
+
#include "iree/compiler/Conversion/LinalgToLLVM/Passes.h"
+#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTargetLinker.h"
#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h"
#include "iree/compiler/Dialect/HAL/Target/TargetRegistry.h"
#include "iree/schemas/dylib_executable_def_generated.h"
@@ -54,6 +57,9 @@
// At this moment we are leaving MLIR LLVM dialect land translating module
// into target independent LLVMIR.
auto llvmModule = mlir::translateModuleToLLVMIR(targetOp.getInnerModule());
+ if (!llvmModule) {
+ return failure();
+ }
// Create invocation function an populate entry_points.
auto executableOp = cast<ExecutableOp>(targetOp.getParentOp());
@@ -64,16 +70,55 @@
std::string funcName =
addCInterface ? "_mlir_ciface_" + std::string(entryPointOp.sym_name())
: std::string(entryPointOp.sym_name());
- dyLibExecutableDef.entry_points.push_back(funcName);
+ dyLibExecutableDef.entry_points.push_back("invoke_" + funcName);
createLLVMInvocationFunc(funcName, llvmModule.get());
}
- if (!llvmModule) {
+ // LLVMIR opt passes.
+ auto targetMachine = createTargetMachine(options_);
+ if (!targetMachine) {
+ targetOp.emitError("Can't create target machine for target triple: " +
+ options_.targetTriple);
return failure();
}
- // TODO(scotttodd): LLVM AOT compilation to
- // dyLibExecutableDef.library_embedded.assign(...)
+ llvmModule->setDataLayout(targetMachine->createDataLayout());
+ llvmModule->setTargetTriple(targetMachine->getTargetTriple().str());
+
+ if (failed(
+ runLLVMIRPasses(options_, targetMachine.get(), llvmModule.get()))) {
+ return targetOp.emitError(
+ "Can't build LLVMIR opt passes for ExecutableOp module");
+ }
+
+ std::string objData;
+ if (failed(runEmitObjFilePasses(targetMachine.get(), llvmModule.get(),
+ &objData))) {
+ return targetOp.emitError("Can't compile LLVMIR module to an obj");
+ }
+
+ std::string sharedLibData;
+ const char* linkerToolPath = std::getenv("IREE_LLVMAOT_LINKER_PATH");
+ if (linkerToolPath != nullptr) {
+ auto sharedLibDataStatus = linkLLVMAOTObjects(linkerToolPath, objData);
+ if (!sharedLibDataStatus.ok()) {
+ return targetOp.emitError(
+ "Can't link executable and generate target dylib, using linker "
+ "toolchain: '" +
+ std::string(linkerToolPath) + "'");
+ }
+ sharedLibData = sharedLibDataStatus.value();
+ } else {
+ auto sharedLibDataStatus = linkLLVMAOTObjectsWithLLDElf(objData);
+ if (!sharedLibDataStatus.ok()) {
+ return targetOp.emitError(
+ "Can't link executable and generate target dylib using "
+ "lld::elf::link");
+ }
+ sharedLibData = sharedLibDataStatus.value();
+ }
+ dyLibExecutableDef.library_embedded = {sharedLibData.begin(),
+ sharedLibData.end()};
::flatbuffers::FlatBufferBuilder fbb;
auto executableOffset =
@@ -109,8 +154,15 @@
std::function<LLVMTargetOptions()> queryOptions) {
getLLVMTargetOptionsFromFlags();
static TargetBackendRegistration registration("dylib-llvm-aot", [=]() {
- // Initalize registered targets.
- llvm::InitializeNativeTarget();
+#define INIT_LLVM_TARGET(TargetName) \
+ LLVMInitialize##TargetName##Target(); \
+ LLVMInitialize##TargetName##TargetMC(); \
+ LLVMInitialize##TargetName##TargetInfo(); \
+ LLVMInitialize##TargetName##AsmPrinter(); \
+ LLVMInitialize##TargetName##AsmParser();
+ INIT_LLVM_TARGET(X86)
+ INIT_LLVM_TARGET(ARM)
+ INIT_LLVM_TARGET(AArch64)
return std::make_unique<LLVMAOTTargetBackend>(queryOptions());
});
}
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTargetLinker.h b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTargetLinker.h
new file mode 100644
index 0000000..764ad02
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTargetLinker.h
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+//
+// 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
+//
+// https://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.
+//
+
+#ifndef IREE_COMPILER_DIALECT_HAL_TARGET_LLVM_AOT_TARGET_LINKER_H_
+#define IREE_COMPILER_DIALECT_HAL_TARGET_LLVM_AOT_TARGET_LINKER_H_
+
+#include <string>
+
+#include "iree/base/file_io.h"
+#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+// Calls linker tool to link objData and returns shared library blob.
+iree::StatusOr<std::string> linkLLVMAOTObjects(
+ const std::string& linkerToolPath, const std::string& objData);
+// Use lld::elf::link for linking objData and returns shared library blob.
+iree::StatusOr<std::string> linkLLVMAOTObjectsWithLLDElf(
+ const std::string& objData);
+
+} // namespace HAL
+} // namespace IREE
+} // namespace iree_compiler
+} // namespace mlir
+
+#endif // IREE_COMPILER_DIALECT_HAL_TARGET_LLVM_AOT_TARGET_LINKER_H_
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.cpp b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.cpp
index ede5f9d..cb2a526 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.cpp
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.cpp
@@ -15,6 +15,7 @@
#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
@@ -31,15 +32,15 @@
namespace HAL {
std::unique_ptr<llvm::TargetMachine> createTargetMachine(
- const LLVMTargetOptions& options) {
+ const LLVMTargetOptions& targetOptions) {
std::string errorMessage;
- auto target =
- llvm::TargetRegistry::lookupTarget(options.targetTriple, errorMessage);
+ auto target = llvm::TargetRegistry::lookupTarget(targetOptions.targetTriple,
+ errorMessage);
if (!target) return nullptr;
// TODO(ataei): Once we have an AOT backend pass cpu and cpu-features
std::unique_ptr<llvm::TargetMachine> machine(target->createTargetMachine(
- options.targetTriple, "generic" /* cpu e.g k8*/,
- "" /* cpu features e.g avx512fma*/, {}, {}));
+ targetOptions.targetTriple, "generic" /* cpu e.g k8*/,
+ "" /* cpu features e.g avx512fma*/, targetOptions.options, {}));
return machine;
}
@@ -82,7 +83,7 @@
}
LogicalResult runLLVMIRPasses(const LLVMTargetOptions& options,
- std::unique_ptr<llvm::TargetMachine> machine,
+ llvm::TargetMachine* machine,
llvm::Module* module) {
llvm::LoopAnalysisManager loopAnalysisManager;
llvm::FunctionAnalysisManager functionAnalysisManager;
@@ -93,8 +94,8 @@
llvm::StandardInstrumentations standardInstrumentations;
standardInstrumentations.registerCallbacks(passInstrumentationCallbacks);
- llvm::PassBuilder passBuilder(machine.get(), options.pipelineTuningOptions,
- {}, &passInstrumentationCallbacks);
+ llvm::PassBuilder passBuilder(machine, options.pipelineTuningOptions, {},
+ &passInstrumentationCallbacks);
llvm::AAManager aa = passBuilder.buildDefaultAAPipeline();
functionAnalysisManager.registerPass([&] { return std::move(aa); });
@@ -114,6 +115,28 @@
return success();
}
+LogicalResult runEmitObjFilePasses(llvm::TargetMachine* machine,
+ llvm::Module* module, std::string* objData) {
+ llvm::SmallVector<char, 0> stream_buffer;
+ {
+ // TODO(ataei): Use non legacy pass mamanger for this.
+ llvm::legacy::PassManager passManager;
+ passManager.add(
+ new llvm::TargetLibraryInfoWrapperPass(machine->getTargetTriple()));
+ llvm::raw_svector_ostream ostream(stream_buffer);
+ if (machine->addPassesToEmitFile(passManager, ostream,
+ /*DwoOut=*/nullptr,
+ llvm::CGFT_ObjectFile)) {
+ return failure();
+ }
+ passManager.run(*module);
+ }
+ // TODO(ataei): This is a work around stream truncation when directly write to
+ // string.
+ *objData = std::string(stream_buffer.begin(), stream_buffer.end());
+ return success();
+}
+
} // namespace HAL
} // namespace IREE
} // namespace iree_compiler
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h
index 99fa937..199e36f 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h
@@ -36,9 +36,13 @@
// Creates and runs LLVMIR optimization passes defined in LLVMTargetOptions.
LogicalResult runLLVMIRPasses(const LLVMTargetOptions& options,
- std::unique_ptr<llvm::TargetMachine> machine,
+ llvm::TargetMachine* machine,
llvm::Module* module);
+// Emits compiled module obj for the target machine.
+LogicalResult runEmitObjFilePasses(llvm::TargetMachine* machine,
+ llvm::Module* module, std::string* objData);
+
} // namespace HAL
} // namespace IREE
} // namespace iree_compiler
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRTarget.cpp b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRTarget.cpp
index af5f3b2..98c0bf4 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRTarget.cpp
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRTarget.cpp
@@ -74,8 +74,8 @@
options_.targetTriple);
return failure();
}
- if (failed(runLLVMIRPasses(options_, std::move(targetMachine),
- llvmModule.get()))) {
+ if (failed(
+ runLLVMIRPasses(options_, targetMachine.get(), llvmModule.get()))) {
return targetOp.emitError(
"Can't build LLVMIR opt passes for ExecutableOp module");
}
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.cpp b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.cpp
index c82e7d0..e71beac 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.cpp
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.cpp
@@ -14,7 +14,10 @@
#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Host.h"
+#include "llvm/Target/TargetOptions.h"
namespace mlir {
namespace iree_compiler {
@@ -33,12 +36,27 @@
targetOptions.pipelineTuningOptions.SLPVectorization = true;
// LLVM -O3.
targetOptions.optLevel = llvm::PassBuilder::OptimizationLevel::O3;
+ targetOptions.options.FloatABIType = llvm::FloatABI::Hard;
return targetOptions;
}
LLVMTargetOptions getLLVMTargetOptionsFromFlags() {
- // TODO(ataei): Add flags and construct options.
- return getDefaultLLVMTargetOptions();
+ auto llvmTargetOptions = getDefaultLLVMTargetOptions();
+
+ static llvm::cl::opt<std::string> clTargetTriple(
+ "iree-llvm-target-triple", llvm::cl::desc("LLVM target machine triple"),
+ llvm::cl::init(llvmTargetOptions.targetTriple));
+ static llvm::cl::opt<bool> clSoftFloat(
+ "iree-llvm-enable-msoft-float-abi",
+ llvm::cl::desc("LLVM target codegen enables soft float abi e.g "
+ "-mfloat-abi=softfp"),
+ llvm::cl::init(false));
+
+ llvmTargetOptions.targetTriple = clTargetTriple;
+ if (clSoftFloat) {
+ llvmTargetOptions.options.FloatABIType = llvm::FloatABI::Soft;
+ }
+ return llvmTargetOptions;
}
} // namespace HAL
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.h b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.h
index d07dbe0..4893566 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.h
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/LLVMTargetOptions.h
@@ -16,6 +16,7 @@
#define IREE_COMPILER_DIALECT_HAL_TARGET_LLVM_LLVMTARGETOPTIONS_H_
#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Target/TargetOptions.h"
namespace mlir {
namespace iree_compiler {
@@ -25,6 +26,7 @@
struct LLVMTargetOptions {
llvm::PipelineTuningOptions pipelineTuningOptions;
llvm::PassBuilder::OptimizationLevel optLevel;
+ llvm::TargetOptions options;
std::string targetTriple;
};
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/internal/BUILD b/iree/compiler/Dialect/HAL/Target/LLVM/internal/BUILD
new file mode 100644
index 0000000..97cc95a
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/internal/BUILD
@@ -0,0 +1,27 @@
+# Copyright 2020 Google LLC
+#
+# 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
+#
+# https://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.
+
+package(
+ default_visibility = ["//visibility:public"],
+ licenses = ["notice"], # Apache 2.0
+)
+
+cc_library(
+ name = "LLVMAOTTargetLinker_internal",
+ srcs = ["LLVMAOTTargetLinker.cpp"],
+ deps = [
+ "//iree/base:file_io",
+ "//iree/compiler/Dialect/HAL/Target/LLVM:LLVMAOTTargetLinker_hdrs",
+ ],
+)
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/internal/CMakeLists.txt b/iree/compiler/Dialect/HAL/Target/LLVM/internal/CMakeLists.txt
new file mode 100644
index 0000000..3bb63dd
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/internal/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright 2020 Google LLC
+#
+# 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
+#
+# https://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.
+
+iree_add_all_subdirs()
+
+iree_cc_library(
+ NAME
+ LLVMAOTTargetLinker_internal
+ SRCS
+ "LLVMAOTTargetLinker.cpp"
+ DEPS
+ iree::base::file_io
+ iree::compiler::Dialect::HAL::Target::LLVM::LLVMAOTTargetLinker_hdrs
+ PUBLIC
+)
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/internal/LLVMAOTTargetLinker.cpp b/iree/compiler/Dialect/HAL/Target/LLVM/internal/LLVMAOTTargetLinker.cpp
new file mode 100644
index 0000000..b883ef7
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/internal/LLVMAOTTargetLinker.cpp
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+//
+// 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
+//
+// https://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.
+
+#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMAOTTargetLinker.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+iree::StatusOr<std::string> linkLLVMAOTObjects(
+ const std::string& linkerToolPath, const std::string& objData) {
+ std::string archiveFile, sharedLibFile;
+ ASSIGN_OR_RETURN(archiveFile, iree::file_io::GetTempFile("objfile"));
+ RETURN_IF_ERROR(iree::file_io::SetFileContents(archiveFile, objData));
+ ASSIGN_OR_RETURN(sharedLibFile, iree::file_io::GetTempFile("dylibfile"));
+ std::string linkingCmd =
+ linkerToolPath + " -shared " + archiveFile + " -o " + sharedLibFile;
+ system(linkingCmd.c_str());
+ return iree::file_io::GetFileContents(sharedLibFile);
+}
+
+iree::StatusOr<std::string> linkLLVMAOTObjectsWithLLDElf(
+ const std::string& objData) {
+ return iree::UnimplementedErrorBuilder(IREE_LOC)
+ << "linkLLVMAOTObjectsWithLLD not implemented yet!";
+}
+
+} // namespace HAL
+} // namespace IREE
+} // namespace iree_compiler
+} // namespace mlir