Adding a skeleton for a HAL backend for JITing serialized LLVMIR executables.

PiperOrigin-RevId: 293898800
diff --git a/iree/hal/llvmjit/BUILD b/iree/hal/llvmjit/BUILD
new file mode 100644
index 0000000..a82ce91
--- /dev/null
+++ b/iree/hal/llvmjit/BUILD
@@ -0,0 +1,108 @@
+# 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.
+
+# HAL implementation for jitting CPU code from LLVMIR.
+
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+cc_library(
+    name = "llvmjit_executable",
+    srcs = ["llvmjit_executable.cc"],
+    hdrs = ["llvmjit_executable.h"],
+    deps = [
+        "//iree/base:status",
+        "//iree/hal:allocator",
+        "//iree/hal:executable",
+        "//iree/hal:executable_spec",
+        "@com_google_absl//absl/types:span",
+    ],
+)
+
+cc_library(
+    name = "llvmjit_command_processor",
+    srcs = ["llvmjit_command_processor.cc"],
+    hdrs = ["llvmjit_command_processor.h"],
+    deps = [
+        ":llvmjit_executable",
+        "//iree/base:tracing",
+        "//iree/hal/host:host_local_command_processor",
+    ],
+)
+
+cc_library(
+    name = "llvmjit_executable_cache",
+    srcs = ["llvmjit_executable_cache.cc"],
+    hdrs = ["llvmjit_executable_cache.h"],
+    deps = [
+        ":llvmjit_executable",
+        "//iree/base:source_location",
+        "//iree/base:status",
+        "//iree/base:tracing",
+        "//iree/hal:allocator",
+        "//iree/hal:executable",
+        "//iree/hal:executable_cache",
+        "//iree/hal:executable_format",
+    ],
+)
+
+cc_library(
+    name = "llvmjit_device",
+    srcs = ["llvmjit_device.cc"],
+    hdrs = ["llvmjit_device.h"],
+    deps = [
+        ":llvmjit_command_processor",
+        ":llvmjit_executable_cache",
+        "//iree/base:memory",
+        "//iree/base:status",
+        "//iree/base:tracing",
+        "//iree/hal:command_buffer_validation",
+        "//iree/hal:command_queue",
+        "//iree/hal:device",
+        "//iree/hal:fence",
+        "//iree/hal/host:async_command_queue",
+        "//iree/hal/host:host_event",
+        "//iree/hal/host:host_local_allocator",
+        "//iree/hal/host:host_submission_queue",
+        "//iree/hal/host:inproc_command_buffer",
+        "@com_google_absl//absl/container:inlined_vector",
+        "@com_google_absl//absl/memory",
+        "@com_google_absl//absl/types:span",
+    ],
+)
+
+cc_library(
+    name = "llvmjit_driver",
+    srcs = ["llvmjit_driver.cc"],
+    hdrs = ["llvmjit_driver.h"],
+    deps = [
+        ":llvmjit_device",
+        "//iree/hal:device_info",
+        "//iree/hal:driver",
+    ],
+)
+
+cc_library(
+    name = "llvmjit_driver_module",
+    srcs = ["llvmjit_driver_module.cc"],
+    deps = [
+        ":llvmjit_driver",
+        "//iree/base:init",
+        "//iree/base:status",
+        "//iree/hal:driver_registry",
+    ],
+    alwayslink = 1,
+)
diff --git a/iree/hal/llvmjit/CMakeLists.txt b/iree/hal/llvmjit/CMakeLists.txt
new file mode 100644
index 0000000..81f36ee
--- /dev/null
+++ b/iree/hal/llvmjit/CMakeLists.txt
@@ -0,0 +1,158 @@
+# 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_cc_library(
+  NAME
+    llvmjit_executable_cache
+  HDRS
+    "llvmjit_executable_cache.h"
+  SRCS
+    "llvmjit_executable_cache.cc"
+  DEPS
+    ::llvmjit_executable
+    iree::base::source_location
+    iree::base::status
+    iree::base::tracing
+    iree::hal::allocator
+    iree::hal::executable
+    iree::hal::executable_cache
+    iree::hal::executable_format
+    iree::vm::instance
+    iree::vm::module
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    llvmjit_command_processor
+  HDRS
+    "llvmjit_command_processor.h"
+  SRCS
+    "llvmjit_command_processor.cc"
+  DEPS
+    ::llvmjit_executable
+    iree::base::api_util
+    iree::base::status
+    iree::base::tracing
+    iree::hal::host::host_local_command_processor
+    iree::vm::invocation
+    iree::vm::variant_list
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    llvmjit_device
+  HDRS
+    "llvmjit_device.h"
+  SRCS
+    "llvmjit_device.cc"
+  DEPS
+    ::llvmjit_executable_cache
+    ::llvmjit_command_processor
+    iree::base::memory
+    iree::base::status
+    iree::base::tracing
+    iree::hal::command_buffer_validation
+    iree::hal::command_queue
+    iree::hal::device
+    iree::hal::fence
+    iree::hal::host::async_command_queue
+    iree::hal::host::host_event
+    iree::hal::host::host_local_allocator
+    iree::hal::host::host_submission_queue
+    iree::hal::host::inproc_command_buffer
+    iree::vm::instance
+    iree::vm::module
+    absl::inlined_vector
+    absl::memory
+    absl::span
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    llvmjit_driver
+  HDRS
+    "llvmjit_driver.h"
+  SRCS
+    "llvmjit_driver.cc"
+  DEPS
+    ::llvmjit_device
+    ::llvmjit_module
+    iree::base::api_util
+    iree::base::tracing
+    iree::hal::device_info
+    iree::hal::driver
+    iree::vm::instance
+    iree::vm::module
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    llvmjit_driver_module
+  SRCS
+    "llvmjit_driver_module.cc"
+  DEPS
+    ::llvmjit_driver
+    iree::base::init
+    iree::base::status
+    iree::hal::driver_registry
+  ALWAYSLINK
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    llvmjit_executable
+  HDRS
+    "llvmjit_executable.h"
+  SRCS
+    "llvmjit_executable.cc"
+  DEPS
+    iree::base::api_util
+    iree::base::status
+    iree::base::tracing
+    iree::hal::allocator
+    iree::hal::executable
+    iree::hal::executable_spec
+    iree::vm::bytecode_module
+    iree::vm::context
+    iree::vm::instance
+    iree::vm::module
+    absl::inlined_vector
+    absl::span
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    llvmjit_module
+  HDRS
+    "llvmjit_module.h"
+  SRCS
+    "llvmjit_module.cc"
+  DEPS
+    ::op_kernels
+    iree::base::api
+    iree::base::memory
+    iree::base::ref_ptr
+    iree::base::tracing
+    iree::vm
+    iree::vm::module_abi_cc
+    iree::vm::types
+    absl::span
+  PUBLIC
+)
diff --git a/iree/hal/llvmjit/llvmjit_command_processor.cc b/iree/hal/llvmjit/llvmjit_command_processor.cc
new file mode 100644
index 0000000..29710ce
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_command_processor.cc
@@ -0,0 +1,38 @@
+// 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/hal/llvmjit/llvmjit_command_processor.h"
+
+#include "iree/base/tracing.h"
+#include "iree/hal/llvmjit/llvmjit_executable.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+LLVMJITCommandProcessor::LLVMJITCommandProcessor(
+    Allocator* allocator, CommandBufferModeBitfield mode,
+    CommandCategoryBitfield command_categories)
+    : HostLocalCommandProcessor(allocator, mode, command_categories) {}
+
+LLVMJITCommandProcessor::~LLVMJITCommandProcessor() = default;
+
+Status LLVMJITCommandProcessor::Dispatch(
+    const DispatchRequest& dispatch_request) {
+  IREE_TRACE_SCOPE0("LLVMJITCommandProcessor::Dispatch");
+  return OkStatus();
+}
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
diff --git a/iree/hal/llvmjit/llvmjit_command_processor.h b/iree/hal/llvmjit/llvmjit_command_processor.h
new file mode 100644
index 0000000..ec5eda6
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_command_processor.h
@@ -0,0 +1,35 @@
+// 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_HAL_LLVMJIT_LLVMJIT_COMMAND_PROCESSOR_H_
+#define IREE_HAL_LLVMJIT_LLVMJIT_COMMAND_PROCESSOR_H_
+#include "iree/hal/host/host_local_command_processor.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+class LLVMJITCommandProcessor final : public HostLocalCommandProcessor {
+ public:
+  LLVMJITCommandProcessor(Allocator* allocator, CommandBufferModeBitfield mode,
+                          CommandCategoryBitfield command_categories);
+  ~LLVMJITCommandProcessor() override;
+
+  Status Dispatch(const DispatchRequest& dispatch_request) override;
+};
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
+
+#endif  // IREE_HAL_LLVMJIT_LLVMJIT_COMMAND_PROCESSOR_H_
diff --git a/iree/hal/llvmjit/llvmjit_device.cc b/iree/hal/llvmjit/llvmjit_device.cc
new file mode 100644
index 0000000..185e191
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_device.cc
@@ -0,0 +1,173 @@
+// 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/hal/llvmjit/llvmjit_device.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "iree/base/status.h"
+#include "iree/base/tracing.h"
+#include "iree/hal/command_buffer_validation.h"
+#include "iree/hal/command_queue.h"
+#include "iree/hal/fence.h"
+#include "iree/hal/host/async_command_queue.h"
+#include "iree/hal/host/host_event.h"
+#include "iree/hal/host/host_submission_queue.h"
+#include "iree/hal/host/inproc_command_buffer.h"
+#include "iree/hal/llvmjit/llvmjit_command_processor.h"
+#include "iree/hal/llvmjit/llvmjit_executable_cache.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+namespace {
+
+// A CommandQueue that performs no synchronization (semaphores/fences) and just
+// directly executes command buffers inline.
+//
+// This is meant to be wrapped by SyncCommandQueue or AsyncCommandQueue that
+// themselves perform the synchronization/threading/etc. As such we ignore
+// all semaphores in the provided batches under the assumption that if Submit is
+// being called then all dependencies are valid. The wrapping queue is also
+// responsible for signaling the fence as well as propagating errors in a way
+// that is dependent on how it is performing its synchronization.
+class UnsynchronizedCommandQueue final : public CommandQueue {
+ public:
+  UnsynchronizedCommandQueue(Allocator* allocator, std::string name,
+                             CommandCategoryBitfield supported_categories)
+      : CommandQueue(std::move(name), supported_categories),
+        allocator_(allocator) {}
+  ~UnsynchronizedCommandQueue() override = default;
+
+  Status Submit(absl::Span<const SubmissionBatch> batches,
+                FenceValue fence) override {
+    IREE_TRACE_SCOPE0("UnsynchronizedCommandQueue::Submit");
+    DCHECK_EQ(nullptr, fence.first)
+        << "Fences must be handled by the wrapping queue";
+
+    // Process command buffers and propagate errors asynchronously through the
+    // fence. This ensures that even if we are running synchronously we still
+    // get consistent failure behavior with drivers that are purely async.
+    for (auto& batch : batches) {
+      DCHECK(batch.wait_semaphores.empty() && batch.signal_semaphores.empty())
+          << "Semaphores must be handled by the wrapping queue";
+      RETURN_IF_ERROR(ProcessCommandBuffers(batch.command_buffers));
+    }
+
+    // NOTE: fence is ignored here.
+    return OkStatus();
+  }
+
+  Status WaitIdle(absl::Time deadline) override {
+    // No-op.
+    return OkStatus();
+  }
+
+ private:
+  // Processes each command buffer in-turn with a fresh processor.
+  // This ensures we don't have any state that can carry across buffers.
+  Status ProcessCommandBuffers(
+      absl::Span<CommandBuffer* const> command_buffers) {
+    IREE_TRACE_SCOPE0("UnsynchronizedCommandQueue::ProcessCommandBuffers");
+    for (auto* command_buffer : command_buffers) {
+      auto* inproc_command_buffer =
+          static_cast<InProcCommandBuffer*>(command_buffer->impl());
+      LLVMJITCommandProcessor command_processor(
+          allocator_, command_buffer->mode(), supported_categories());
+      RETURN_IF_ERROR(inproc_command_buffer->Process(&command_processor));
+    }
+    return OkStatus();
+  }
+
+  Allocator* const allocator_;
+};
+
+}  // namespace
+
+LLVMJITDevice::LLVMJITDevice(DeviceInfo device_info)
+    : Device(std::move(device_info)) {
+  // We currently only expose a single command queue.
+  auto command_queue = absl::make_unique<UnsynchronizedCommandQueue>(
+      &allocator_, "cpu0",
+      CommandCategory::kTransfer | CommandCategory::kDispatch);
+
+  // TODO(benvanik): allow injection of the wrapper type to support
+  // SyncCommandQueue without always linking in both.
+  auto async_command_queue =
+      absl::make_unique<AsyncCommandQueue>(std::move(command_queue));
+  command_queues_.push_back(std::move(async_command_queue));
+}
+
+LLVMJITDevice::~LLVMJITDevice() = default;
+
+ref_ptr<ExecutableCache> LLVMJITDevice::CreateExecutableCache() {
+  return make_ref<LLVMJITExecutableCache>(&allocator_);
+}
+
+StatusOr<ref_ptr<CommandBuffer>> LLVMJITDevice::CreateCommandBuffer(
+    CommandBufferModeBitfield mode,
+    CommandCategoryBitfield command_categories) {
+  // TODO(b/140026716): conditionally enable validation.
+  auto impl =
+      make_ref<InProcCommandBuffer>(&allocator_, mode, command_categories);
+  return WrapCommandBufferWithValidation(std::move(impl));
+}
+
+StatusOr<ref_ptr<Event>> LLVMJITDevice::CreateEvent() {
+  return make_ref<HostEvent>();
+}
+
+StatusOr<ref_ptr<BinarySemaphore>> LLVMJITDevice::CreateBinarySemaphore(
+    bool initial_value) {
+  IREE_TRACE_SCOPE0("LLVMJITDevice::CreateBinarySemaphore");
+  return make_ref<HostBinarySemaphore>(initial_value);
+}
+
+StatusOr<ref_ptr<TimelineSemaphore>> LLVMJITDevice::CreateTimelineSemaphore(
+    uint64_t initial_value) {
+  IREE_TRACE_SCOPE0("LLVMJITDevice::CreateTimelineSemaphore");
+
+  // TODO(b/140141417): implement timeline semaphores.
+  return UnimplementedErrorBuilder(IREE_LOC)
+         << "Timeline semaphores not yet implemented";
+}
+
+StatusOr<ref_ptr<Fence>> LLVMJITDevice::CreateFence(uint64_t initial_value) {
+  IREE_TRACE_SCOPE0("LLVMJITDevice::CreateFence");
+  return make_ref<HostFence>(initial_value);
+}
+
+Status LLVMJITDevice::WaitAllFences(absl::Span<const FenceValue> fences,
+                                    absl::Time deadline) {
+  IREE_TRACE_SCOPE0("LLVMJITDevice::WaitAllFences");
+  return HostFence::WaitForFences(fences, /*wait_all=*/true, deadline);
+}
+
+StatusOr<int> LLVMJITDevice::WaitAnyFence(absl::Span<const FenceValue> fences,
+                                          absl::Time deadline) {
+  IREE_TRACE_SCOPE0("LLVMJITDevice::WaitAnyFence");
+  return HostFence::WaitForFences(fences, /*wait_all=*/false, deadline);
+}
+
+Status LLVMJITDevice::WaitIdle(absl::Time deadline) {
+  for (auto& command_queue : command_queues_) {
+    RETURN_IF_ERROR(command_queue->WaitIdle(deadline));
+  }
+  return OkStatus();
+}
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
diff --git a/iree/hal/llvmjit/llvmjit_device.h b/iree/hal/llvmjit/llvmjit_device.h
new file mode 100644
index 0000000..ca0f274
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_device.h
@@ -0,0 +1,72 @@
+// 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_HAL_LLVMJIT_LLVMJIT_DEVICE_H_
+#define IREE_HAL_LLVMJIT_LLVMJIT_DEVICE_H_
+
+#include "absl/container/inlined_vector.h"
+#include "absl/types/span.h"
+#include "iree/base/memory.h"
+#include "iree/hal/device.h"
+#include "iree/hal/host/host_local_allocator.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+class LLVMJITDevice final : public Device {
+ public:
+  explicit LLVMJITDevice(DeviceInfo device_info);
+  ~LLVMJITDevice() override;
+
+  Allocator* allocator() const override { return &allocator_; }
+
+  absl::Span<CommandQueue*> dispatch_queues() const override {
+    return RawPtrSpan(absl::MakeSpan(command_queues_));
+  }
+
+  absl::Span<CommandQueue*> transfer_queues() const override {
+    return RawPtrSpan(absl::MakeSpan(command_queues_));
+  }
+
+  ref_ptr<ExecutableCache> CreateExecutableCache() override;
+
+  StatusOr<ref_ptr<CommandBuffer>> CreateCommandBuffer(
+      CommandBufferModeBitfield mode,
+      CommandCategoryBitfield command_categories) override;
+
+  StatusOr<ref_ptr<Event>> CreateEvent() override;
+
+  StatusOr<ref_ptr<BinarySemaphore>> CreateBinarySemaphore(
+      bool initial_value) override;
+  StatusOr<ref_ptr<TimelineSemaphore>> CreateTimelineSemaphore(
+      uint64_t initial_value) override;
+
+  StatusOr<ref_ptr<Fence>> CreateFence(uint64_t initial_value) override;
+  Status WaitAllFences(absl::Span<const FenceValue> fences,
+                       absl::Time deadline) override;
+  StatusOr<int> WaitAnyFence(absl::Span<const FenceValue> fences,
+                             absl::Time deadline) override;
+
+  Status WaitIdle(absl::Time deadline) override;
+
+ private:
+  mutable HostLocalAllocator allocator_;
+  mutable absl::InlinedVector<std::unique_ptr<CommandQueue>, 1> command_queues_;
+};
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
+
+#endif  // IREE_HAL_LLVMJIT_LLVMJIT_DEVICE_H_
diff --git a/iree/hal/llvmjit/llvmjit_driver.cc b/iree/hal/llvmjit/llvmjit_driver.cc
new file mode 100644
index 0000000..3c92f47
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_driver.cc
@@ -0,0 +1,61 @@
+// 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/hal/llvmjit/llvmjit_driver.h"
+
+#include <memory>
+
+#include "iree/hal/device_info.h"
+#include "iree/hal/llvmjit/llvmjit_device.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+namespace {
+
+DeviceInfo GetDefaultDeviceInfo() {
+  DeviceFeatureBitfield supported_features = DeviceFeature::kNone;
+  // TODO(benvanik): implement debugging/profiling features.
+  // supported_features |= DeviceFeature::kDebugging;
+  // supported_features |= DeviceFeature::kCoverage;
+  // supported_features |= DeviceFeature::kProfiling;
+  DeviceInfo device_info("llvm", supported_features);
+  // TODO(benvanik): device info.
+  return device_info;
+}
+
+}  // namespace
+
+LLVMJITDriver::LLVMJITDriver() : Driver("interpreter") {}
+
+LLVMJITDriver::~LLVMJITDriver() = default;
+
+StatusOr<std::vector<DeviceInfo>> LLVMJITDriver::EnumerateAvailableDevices() {
+  std::vector<DeviceInfo> device_infos;
+  device_infos.push_back(GetDefaultDeviceInfo());
+  return device_infos;
+}
+
+StatusOr<ref_ptr<Device>> LLVMJITDriver::CreateDefaultDevice() {
+  return CreateDevice(0);
+}
+
+StatusOr<ref_ptr<Device>> LLVMJITDriver::CreateDevice(
+    DriverDeviceID device_id) {
+  auto device = make_ref<LLVMJITDevice>(GetDefaultDeviceInfo());
+  return device;
+}
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
diff --git a/iree/hal/llvmjit/llvmjit_driver.h b/iree/hal/llvmjit/llvmjit_driver.h
new file mode 100644
index 0000000..7a53b60
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_driver.h
@@ -0,0 +1,39 @@
+// 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_HAL_LLVMJIT_LLVMJIT_DRIVER_H_
+#define IREE_HAL_LLVMJIT_LLVMJIT_DRIVER_H_
+
+#include "iree/hal/driver.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+class LLVMJITDriver final : public Driver {
+ public:
+  LLVMJITDriver();
+  ~LLVMJITDriver() override;
+
+  StatusOr<std::vector<DeviceInfo>> EnumerateAvailableDevices() override;
+
+  StatusOr<ref_ptr<Device>> CreateDefaultDevice() override;
+
+  StatusOr<ref_ptr<Device>> CreateDevice(DriverDeviceID device_id) override;
+};
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
+
+#endif  // IREE_HAL_LLVMJIT_LLVMJIT_DRIVER_H_
diff --git a/iree/hal/llvmjit/llvmjit_driver_module.cc b/iree/hal/llvmjit/llvmjit_driver_module.cc
new file mode 100644
index 0000000..d3a12c7
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_driver_module.cc
@@ -0,0 +1,37 @@
+// 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 <memory>
+
+#include "iree/base/init.h"
+#include "iree/base/status.h"
+#include "iree/hal/driver_registry.h"
+#include "iree/hal/llvmjit/llvmjit_driver.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+static StatusOr<ref_ptr<Driver>> CreateLLVMJITDriver() {
+  return make_ref<LLVMJITDriver>();
+}
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
+
+IREE_REGISTER_MODULE_INITIALIZER(iree_hal_llvm_driver, {
+  QCHECK_OK(::iree::hal::DriverRegistry::shared_registry()->Register(
+      "llvm", ::iree::hal::llvmjit::CreateLLVMJITDriver));
+});
+IREE_REGISTER_MODULE_INITIALIZER_SEQUENCE(iree_hal, iree_hal_llvm_driver);
diff --git a/iree/hal/llvmjit/llvmjit_executable.cc b/iree/hal/llvmjit/llvmjit_executable.cc
new file mode 100644
index 0000000..0ad88bf
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_executable.cc
@@ -0,0 +1,51 @@
+// 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/hal/llvmjit/llvmjit_executable.h"
+
+#include <iostream>
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+// static
+StatusOr<ref_ptr<LLVMJITExecutable>> LLVMJITExecutable::Load(
+    hal::Allocator* allocator, ExecutableSpec spec, bool allow_aliasing_data) {
+  // Allocate the executable now.
+  // We do this here so that if we need to clone the data we are passing that
+  // to the VM loader instead of the data we may not have access to later.
+
+  auto executable =
+      make_ref<LLVMJITExecutable>(allocator, spec, allow_aliasing_data);
+
+  return executable;
+}
+
+LLVMJITExecutable::LLVMJITExecutable(hal::Allocator* allocator,
+                                     ExecutableSpec spec,
+                                     bool allow_aliasing_data)
+    : spec_(spec) {
+  if (!allow_aliasing_data) {
+    // Clone data.
+    cloned_executable_data_ = {spec.executable_data.begin(),
+                               spec.executable_data.end()};
+    spec_.executable_data = absl::MakeConstSpan(cloned_executable_data_);
+  }
+}
+
+LLVMJITExecutable::~LLVMJITExecutable() = default;
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
diff --git a/iree/hal/llvmjit/llvmjit_executable.h b/iree/hal/llvmjit/llvmjit_executable.h
new file mode 100644
index 0000000..d9be4b2
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_executable.h
@@ -0,0 +1,49 @@
+// 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_HAL_LLVMJIT_LLVMJIT_EXECUTABLE_H_
+#define IREE_HAL_LLVMJIT_LLVMJIT_EXECUTABLE_H_
+
+#include <vector>
+
+#include "absl/types/span.h"
+#include "iree/base/status.h"
+#include "iree/hal/allocator.h"
+#include "iree/hal/executable.h"
+#include "iree/hal/executable_spec.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+class LLVMJITExecutable final : public Executable {
+ public:
+  static StatusOr<ref_ptr<LLVMJITExecutable>> Load(hal::Allocator* allocator,
+                                                   ExecutableSpec spec,
+                                                   bool allow_aliasing_data);
+  LLVMJITExecutable(hal::Allocator* allocator, ExecutableSpec spec,
+                    bool allow_aliasing_data);
+  ~LLVMJITExecutable() override;
+
+  bool supports_debugging() const override { return false; }
+
+ private:
+  ExecutableSpec spec_;
+  std::vector<uint8_t> cloned_executable_data_;
+};
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
+
+#endif  // IREE_HAL_LLVMJIT_LLVMJIT_EXECUTABLE_H_
diff --git a/iree/hal/llvmjit/llvmjit_executable_cache.cc b/iree/hal/llvmjit/llvmjit_executable_cache.cc
new file mode 100644
index 0000000..43d82d3
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_executable_cache.cc
@@ -0,0 +1,55 @@
+// 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/hal/llvmjit/llvmjit_executable_cache.h"
+
+#include "iree/base/source_location.h"
+#include "iree/base/status.h"
+#include "iree/base/tracing.h"
+#include "iree/hal/executable_format.h"
+#include "iree/hal/llvmjit/llvmjit_executable.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+LLVMJITExecutableCache::LLVMJITExecutableCache(hal::Allocator* allocator)
+    : allocator_(allocator) {}
+
+LLVMJITExecutableCache::~LLVMJITExecutableCache() = default;
+
+bool LLVMJITExecutableCache::CanPrepareFormat(ExecutableFormat format) const {
+  return format == kExecutableFormatLLVM;
+}
+
+StatusOr<ref_ptr<Executable>> LLVMJITExecutableCache::PrepareExecutable(
+    ExecutableCachingModeBitfield mode, const ExecutableSpec& spec) {
+  IREE_TRACE_SCOPE0("LLVMJITExecutableCache::PrepareExecutable");
+  if (!CanPrepareFormat(spec.format)) {
+    return UnimplementedErrorBuilder(IREE_LOC)
+           << "Unsupported format: " << spec.format;
+  }
+
+  // Wrap the data (or copy it).
+  bool allow_aliasing_data =
+      AllBitsSet(mode, ExecutableCachingMode::kAliasProvidedData);
+  ASSIGN_OR_RETURN(
+      auto executable,
+      LLVMJITExecutable::Load(allocator_, spec, !allow_aliasing_data));
+
+  return executable;
+}
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
diff --git a/iree/hal/llvmjit/llvmjit_executable_cache.h b/iree/hal/llvmjit/llvmjit_executable_cache.h
new file mode 100644
index 0000000..a8315de
--- /dev/null
+++ b/iree/hal/llvmjit/llvmjit_executable_cache.h
@@ -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.
+
+#ifndef IREE_HAL_LLVMJIT_EXECUTABLE_CACHE_H_
+#define IREE_HAL_LLVMJIT_EXECUTABLE_CACHE_H_
+
+#include "iree/hal/allocator.h"
+#include "iree/hal/executable.h"
+#include "iree/hal/executable_cache.h"
+
+namespace iree {
+namespace hal {
+namespace llvmjit {
+
+class LLVMJITExecutableCache final : public ExecutableCache {
+ public:
+  explicit LLVMJITExecutableCache(hal::Allocator* allocator);
+  ~LLVMJITExecutableCache() override;
+
+  bool CanPrepareFormat(ExecutableFormat format) const override;
+
+  StatusOr<ref_ptr<Executable>> PrepareExecutable(
+      ExecutableCachingModeBitfield mode, const ExecutableSpec& spec) override;
+
+ private:
+  hal::Allocator* allocator_;
+};
+}  // namespace llvmjit
+}  // namespace hal
+}  // namespace iree
+
+#endif  // IREE_HAL_LLVMJIT_EXECUTABLE_CACHE_H_
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index 36587ea..06eaee0 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -41,6 +41,7 @@
     # "//iree/hal/dawn:dawn_driver_module",
     "//iree/hal/vmla:vmla_driver_module",
     "//iree/hal/vulkan:vulkan_driver_module",
+    "//iree/hal/llvmjit:llvmjit_driver_module",
 ]
 
 cc_binary(
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index e8bd8db..546a670 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -55,6 +55,7 @@
     # iree::hal::dawn::dawn_driver_module
     iree::hal::vmla::vmla_driver_module
     iree::hal::vulkan::vulkan_driver_module
+    iree::hal::llvmjit::llvmjit_driver_module
 )
 add_executable(iree-benchmark-module ALIAS iree_tools_iree-benchmark-module)