Adding HAL dialect skeleton for executable lowering.

PiperOrigin-RevId: 282396945
diff --git a/iree/compiler/Dialect/HAL/IR/BUILD b/iree/compiler/Dialect/HAL/IR/BUILD
new file mode 100644
index 0000000..d8a1c30
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/BUILD
@@ -0,0 +1,105 @@
+# Copyright 2019 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.
+
+load("@local_config_mlir//:tblgen.bzl", "gentbl")
+
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+exports_files(["HALBase.td"])
+
+filegroup(
+    name = "td_files",
+    srcs = glob(["*.td"]),
+)
+
+cc_library(
+    name = "IR",
+    srcs = [
+        "HALDialect.cpp",
+        "HALEnums.cpp.inc",
+        "HALOpFolders.cpp",
+        "HALOpInterface.cpp.inc",
+        "HALOps.cpp",
+        "HALOps.cpp.inc",
+        "HALTypes.cpp",
+    ],
+    hdrs = [
+        "HALDialect.h",
+        "HALEnums.h.inc",
+        "HALOpInterface.h.inc",
+        "HALOps.h",
+        "HALOps.h.inc",
+        "HALTypes.h",
+    ],
+    deps = [
+        ":HALEnumsGen",
+        ":HALOpInterfaceGen",
+        ":HALOpsGen",
+        "//iree/compiler/Dialect",
+        "@llvm//:support",
+        "@local_config_mlir//:IR",
+        "@local_config_mlir//:StandardOps",
+        "@local_config_mlir//:Support",
+        "@local_config_mlir//:TransformUtils",
+    ],
+    alwayslink = 1,
+)
+
+gentbl(
+    name = "HALEnumsGen",
+    tbl_outs = [
+        ("-gen-enum-decls", "HALEnums.h.inc"),
+        ("-gen-enum-defs", "HALEnums.cpp.inc"),
+    ],
+    tblgen = "@local_config_mlir//:mlir-tblgen",
+    td_file = "HALBase.td",
+    td_srcs = [
+        ":td_files",
+        "//iree/compiler/Dialect:td_files",
+        "@local_config_mlir//:OpBaseTdFiles",
+    ],
+)
+
+gentbl(
+    name = "HALOpInterfaceGen",
+    tbl_outs = [
+        ("-gen-op-interface-decls", "HALOpInterface.h.inc"),
+        ("-gen-op-interface-defs", "HALOpInterface.cpp.inc"),
+    ],
+    tblgen = "@local_config_mlir//:mlir-tblgen",
+    td_file = "HALBase.td",
+    td_srcs = [
+        ":td_files",
+        "//iree/compiler/Dialect:td_files",
+        "@local_config_mlir//:OpBaseTdFiles",
+    ],
+)
+
+gentbl(
+    name = "HALOpsGen",
+    tbl_outs = [
+        ("-gen-op-decls", "HALOps.h.inc"),
+        ("-gen-op-defs", "HALOps.cpp.inc"),
+    ],
+    tblgen = "@local_config_mlir//:mlir-tblgen",
+    td_file = "HALOps.td",
+    td_srcs = [
+        ":td_files",
+        "//iree/compiler/Dialect:td_files",
+        "@local_config_mlir//:OpBaseTdFiles",
+    ],
+)
diff --git a/iree/compiler/Dialect/HAL/IR/HALBase.td b/iree/compiler/Dialect/HAL/IR/HALBase.td
new file mode 100644
index 0000000..003c09b
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALBase.td
@@ -0,0 +1,213 @@
+// Copyright 2019 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_DIALECT_HAL_BASE
+#define IREE_DIALECT_HAL_BASE
+
+include "iree/compiler/Dialect/CommonBase.td"
+
+//===----------------------------------------------------------------------===//
+// IREE HAL (Hardware Abstraction Layer) dialect
+//===----------------------------------------------------------------------===//
+
+def HAL_Dialect : Dialect {
+  let name = "hal";
+  let cppNamespace = "IREE::HAL";
+
+  let summary = [{
+    A dialect representing operations against the IREE HAL.
+  }];
+  let description = [{
+    This can be thought of as a Vulkan-like model with all of the graphics bits
+    chopped out.
+
+    The type set is limited to those that can be represented in the IREE HAL
+    design: buffers and views, synchronization primitives like semaphores, and
+    and command buffers. The intent is that if a device could implement the HAL
+    interface the sequencer ops could run on that device, such as being able to
+    run on a GPU via indirect command buffers.
+
+    Though this is mostly a 1:1 mapping to the iree::hal API there are some
+    methods omitted as they are not likely to be needed in IR. It's assumed that
+    either sequencer interfaces will encapsulate the logic (such as device
+    resolution) or that certain features are unsafe to expose to user-defined
+    input.
+  }];
+}
+
+//===----------------------------------------------------------------------===//
+// HAL types
+//===----------------------------------------------------------------------===//
+
+def HAL_Allocator : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::AllocatorType>()">,
+    "allocator"> {
+  let typeDescription = [{
+    Allocates buffers for a particular device memory space.
+  }];
+}
+
+def HAL_Buffer : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::BufferType>()">,
+    "buffer"> {
+  let typeDescription = [{
+    A memory buffer with a specific memory_type that is used to describe the
+    capabilities and behavior of the backing memory of the buffer. Buffers may
+    be any mix of host-accessible, host-coherent, or device-accessible for
+    various usages. Depending on these memory types the buffers may be mapped
+    for access on the host as memory though certain restrictions may be imposed.
+  }];
+}
+
+def HAL_CommandBuffer : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::CommandBufferType>()">,
+    "command_buffer"> {
+  let typeDescription = [{
+    Asynchronous command buffer recording interface. Commands are recorded by
+    the implementation for later submission to command queues.
+  }];
+}
+
+def HAL_Device : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::DeviceType>()">,
+    "device"> {
+  let typeDescription = [{
+    Logical device instance.
+  }];
+}
+
+def HAL_Event : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::EventType>()">,
+    "event"> {
+  let typeDescription = [{
+    Events are used for defining synchronization scopes within CommandBuffers.
+    An event only exists within a single CommandBuffer and must not be used
+    across CommandBuffers from the same device or others.
+  }];
+}
+def HAL_EventList : TupleOf<[RefPtrOf<HAL_Event>]>;
+
+def HAL_Executable : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::ExecutableType>()">,
+    "executable"> {
+  let typeDescription = [{
+    A prepared and ready-to-dispatch executable.
+  }];
+}
+
+def HAL_ExecutableCache : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::ExecutableCacheType>()">,
+    "executable_cache"> {
+  let typeDescription = [{
+    A cache of prepared executables for a particular device.
+    Caches may be shared across multiple devices from the same driver or
+    specific to individual devices. Caches may persist prepared executables
+    across process launches or reprepare them each run. Callers should assume
+    that the cache is a no-op and the returned Executables only live for as long
+    as the cache does.
+  }];
+}
+
+def HAL_Fence : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::FenceType>()">,
+    "fence"> {
+  let typeDescription = [{
+    Synchronization mechanism for device->host notification.
+    Fences behave like timeline semaphores and contain a monotonically
+    increasing uint64_t payload. They may be waited on any number of times -
+    even if they have already been signaled.
+  }];
+}
+
+def HAL_RingBuffer : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::RingBufferType>()">,
+    "ring_buffer"> {
+  let typeDescription = [{
+    Ringbuffer used for transient buffer allocation.
+  }];
+}
+
+def HAL_Semaphore : DialectType<
+    HAL_Dialect,
+    CPred<"$_self.isa<IREE::HAL::SemaphoreType>()">,
+    "semaphore"> {
+  let typeDescription = [{
+    A synchronization primitive used to indicate submission dependencies.
+    Semaphores are either of type binary (signaled or unsignaled) or timeline
+    (uint64_t payload with >= semantics).
+  }];
+}
+
+def HAL_OrdinalAttr : IntegerAttrBase<I32, "32-bit integer ordinal attribute">;
+
+def HAL_ExecutableFormatAttr : IntegerAttrBase<I32, "uint32_t">;
+def HAL_ExecutableDataAttr : IntElementsAttr<8>;
+
+def HAL_DeviceSize : TypeAlias<I32>;
+def HAL_DeviceSizeAttr : IntegerAttrBase<I32, "device_size_t">;
+
+def HAL_HostSize : TypeAlias<I32>;
+def HAL_HostSizeAttr : IntegerAttrBase<I32, "size_t">;
+
+def HAL_TimelineValue : TypeAlias<I32>;
+
+def HAL_Status : TypeAlias<I32>;
+
+def HAL_Dim : I<32>;
+def HAL_Dims : VectorOf<[HAL_Dim]>;
+def HAL_Shape : TypeAlias<HAL_Dims>;
+
+def HAL_Workload : VectorOfLengthAndType<[3], [I32]> {
+  let typeDescription = [{
+    An (X, Y, Z) invocation count describing the workload of an operation.
+  }];
+}
+
+def HAL_HostBufferRef : AnyTypeOf<[
+  RefPtrOf<ByteBufferType>,
+  RefPtrOf<MutableByteBufferType>,
+]>;
+
+//===----------------------------------------------------------------------===//
+// Base HAL op classes
+//===----------------------------------------------------------------------===//
+
+def HAL_OpInterface : OpInterface<"HALOp"> {
+  let description = [{
+    Interface for HAL ops.
+  }];
+}
+
+class HAL_Op<string mnemonic, list<OpTrait> traits = []> :
+    Op<HAL_Dialect, mnemonic, !listconcat(traits, [HAL_OpInterface])> {
+  let parser = [{ return parse$cppClass(parser, &result); }];
+  let printer = [{ return print$cppClass(p, *this); }];
+}
+
+class HAL_PureOp<string mnemonic, list<OpTrait> traits = []> :
+    HAL_Op<mnemonic, !listconcat(traits, [NoSideEffect])>;
+
+class HAL_MakeTupleOp<string mnemonic, list<OpTrait> traits = []> :
+    HAL_PureOp<mnemonic, traits>;
+
+#endif  // IREE_DIALECT_HAL_BASE
diff --git a/iree/compiler/Dialect/HAL/IR/HALDialect.cpp b/iree/compiler/Dialect/HAL/IR/HALDialect.cpp
new file mode 100644
index 0000000..620924b
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALDialect.cpp
@@ -0,0 +1,100 @@
+// Copyright 2019 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/IR/HALDialect.h"
+
+#include "iree/compiler/Dialect/HAL/IR/HALOps.h"
+#include "iree/compiler/Dialect/HAL/IR/HALTypes.h"
+#include "mlir/IR/DialectImplementation.h"
+#include "mlir/IR/OpImplementation.h"
+#include "third_party/llvm/llvm/include/llvm/Support/SourceMgr.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+#include "iree/compiler/Dialect/HAL/IR/HALOpInterface.cpp.inc"
+
+static DialectRegistration<HALDialect> hal_dialect;
+
+HALDialect::HALDialect(MLIRContext *context)
+    : Dialect(getDialectNamespace(), context) {
+  addTypes<AllocatorType, BufferType, CommandBufferType, DeviceType, EventType,
+           ExecutableType, ExecutableCacheType, FenceType, RingBufferType,
+           SemaphoreType>();
+
+#define GET_OP_LIST
+  addOperations<
+#include "iree/compiler/Dialect/HAL/IR/HALOps.cpp.inc"
+      >();
+}
+
+//===----------------------------------------------------------------------===//
+// Type printing and parsing
+//===----------------------------------------------------------------------===//
+
+Type HALDialect::parseType(DialectAsmParser &parser) const {
+  StringRef typeName;
+  if (parser.parseKeyword(&typeName)) return Type();
+  auto type =
+      llvm::StringSwitch<Type>(typeName)
+          .Case("allocator", AllocatorType::get(getContext()))
+          .Case("buffer", BufferType::get(getContext()))
+          .Case("command_buffer", CommandBufferType::get(getContext()))
+          .Case("device", DeviceType::get(getContext()))
+          .Case("event", EventType::get(getContext()))
+          .Case("executable", ExecutableType::get(getContext()))
+          .Case("executable_cache", ExecutableCacheType::get(getContext()))
+          .Case("fence", FenceType::get(getContext()))
+          .Case("ring_buffer", RingBufferType::get(getContext()))
+          .Case("semaphore", SemaphoreType::get(getContext()))
+          .Default(nullptr);
+  if (!type) {
+    parser.emitError(parser.getCurrentLocation())
+        << "unknown HAL type: " << typeName;
+  }
+  return type;
+}
+
+void HALDialect::printType(Type type, DialectAsmPrinter &p) const {
+  if (type.isa<AllocatorType>()) {
+    p << "allocator";
+  } else if (type.isa<BufferType>()) {
+    p << "buffer";
+  } else if (type.isa<CommandBufferType>()) {
+    p << "command_buffer";
+  } else if (type.isa<DeviceType>()) {
+    p << "device";
+  } else if (type.isa<EventType>()) {
+    p << "event";
+  } else if (type.isa<ExecutableType>()) {
+    p << "executable";
+  } else if (type.isa<ExecutableCacheType>()) {
+    p << "executable_cache";
+  } else if (type.isa<FenceType>()) {
+    p << "fence";
+  } else if (type.isa<RingBufferType>()) {
+    p << "ring_buffer";
+  } else if (type.isa<SemaphoreType>()) {
+    p << "semaphore";
+  } else {
+    llvm_unreachable("unknown HAL type");
+  }
+}
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/HAL/IR/HALDialect.h b/iree/compiler/Dialect/HAL/IR/HALDialect.h
new file mode 100644
index 0000000..dc30a49
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALDialect.h
@@ -0,0 +1,42 @@
+// Copyright 2019 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_IR_HALDIALECT_H_
+#define IREE_COMPILER_DIALECT_HAL_IR_HALDIALECT_H_
+
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/OpDefinition.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+#include "iree/compiler/Dialect/HAL/IR/HALOpInterface.h.inc"
+
+class HALDialect : public Dialect {
+ public:
+  explicit HALDialect(MLIRContext *context);
+  static StringRef getDialectNamespace() { return "hal"; }
+
+  Type parseType(DialectAsmParser &parser) const override;
+  void printType(Type type, DialectAsmPrinter &p) const override;
+};
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_HAL_IR_HALDIALECT_H_
diff --git a/iree/compiler/Dialect/HAL/IR/HALOpFolders.cpp b/iree/compiler/Dialect/HAL/IR/HALOpFolders.cpp
new file mode 100644
index 0000000..bb34005
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALOpFolders.cpp
@@ -0,0 +1,37 @@
+// Copyright 2019 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/IR/HALDialect.h"
+#include "iree/compiler/Dialect/HAL/IR/HALOps.h"
+#include "llvm/ADT/StringExtras.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/Matchers.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/Support/LogicalResult.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+// TODO(benvanik): folders.
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/HAL/IR/HALOps.cpp b/iree/compiler/Dialect/HAL/IR/HALOps.cpp
new file mode 100644
index 0000000..84d26cc
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALOps.cpp
@@ -0,0 +1,147 @@
+// Copyright 2019 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/IR/HALOps.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/SymbolTable.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+//===----------------------------------------------------------------------===//
+// hal.executable
+//===----------------------------------------------------------------------===//
+
+void ExecutableOp::build(Builder *builder, OperationState &state,
+                         StringRef name) {
+  ensureTerminator(*state.addRegion(), *builder, state.location);
+  state.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
+                     builder->getStringAttr(name));
+}
+
+static ParseResult parseExecutableOp(OpAsmParser &parser,
+                                     OperationState *result) {
+  StringAttr nameAttr;
+  if (failed(parser.parseSymbolName(nameAttr,
+                                    mlir::SymbolTable::getSymbolAttrName(),
+                                    result->attributes)) ||
+      failed(parser.parseOptionalAttrDictWithKeyword(result->attributes))) {
+    return failure();
+  }
+
+  // Parse the module body.
+  auto *body = result->addRegion();
+  if (failed(parser.parseRegion(*body, llvm::None, llvm::None))) {
+    return failure();
+  }
+
+  // Ensure that this module has a valid terminator.
+  ExecutableOp::ensureTerminator(*body, parser.getBuilder(), result->location);
+  return success();
+}
+
+static void printExecutableOp(OpAsmPrinter &p, ExecutableOp op) {
+  p << op.getOperationName() << ' ';
+  p.printSymbolName(op.sym_name());
+  p.printOptionalAttrDictWithKeyword(
+      op.getAttrs(),
+      /*elidedAttrs=*/{mlir::SymbolTable::getSymbolAttrName()});
+  p.printRegion(op.body(), /*printEntryBlockArgs=*/false,
+                /*printBlockTerminators=*/false);
+}
+
+static LogicalResult verifyExecutableOp(ExecutableOp op) {
+  // TODO(benvanik): check export name conflicts.
+  return success();
+}
+
+static ParseResult parseRegionEndOp(OpAsmParser &parser,
+                                    OperationState *result) {
+  return parser.parseOptionalAttrDict(result->attributes);
+}
+
+static void printRegionEndOp(OpAsmPrinter &p, Operation *op) {
+  p << op->getName();
+  p.printOptionalAttrDict(op->getAttrs());
+}
+
+//===----------------------------------------------------------------------===//
+// hal.executable.binary
+//===----------------------------------------------------------------------===//
+
+void ExecutableBinaryOp::build(Builder *builder, OperationState &state,
+                               uint32_t format, std::vector<uint8_t> data) {
+  ensureTerminator(*state.addRegion(), *builder, state.location);
+  state.addAttribute(
+      "format", builder->getIntegerAttr(builder->getIntegerType(32), format));
+  state.addAttribute("data",
+                     DenseIntElementsAttr::get(
+                         VectorType::get({static_cast<int64_t>(data.size())},
+                                         builder->getIntegerType(8)),
+                         data));
+}
+
+static ParseResult parseExecutableBinaryOp(OpAsmParser &parser,
+                                           OperationState *result) {
+  auto *body = result->addRegion();
+  if (failed(parser.parseOptionalAttrDictWithKeyword(result->attributes)) ||
+      failed(parser.parseOptionalRegion(*body, llvm::None, llvm::None))) {
+    return failure();
+  }
+
+  // Ensure that this module has a valid terminator.
+  ExecutableBinaryOp::ensureTerminator(*body, parser.getBuilder(),
+                                       result->location);
+  return success();
+}
+
+static void printExecutableBinaryOp(OpAsmPrinter &p, ExecutableBinaryOp op) {
+  p << op.getOperationName();
+  p.printOptionalAttrDictWithKeyword(
+      op.getAttrs(),
+      /*elidedAttrs=*/{mlir::SymbolTable::getSymbolAttrName()});
+  if (!op.body().empty()) {
+    p.printRegion(op.body(), /*printEntryBlockArgs=*/false,
+                  /*printBlockTerminators=*/false);
+  }
+}
+
+static LogicalResult verifyExecutableBinaryOp(ExecutableBinaryOp op) {
+  // Zero or one ModuleOps allowed.
+  if (std::distance(op.getBlock().getOps<ModuleOp>().begin(),
+                    op.getBlock().getOps<ModuleOp>().end()) > 1) {
+    return op.emitOpError() << "expects zero or one nested std.module ops";
+  }
+
+  // TODO(benvanik): check export name conflicts.
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// TableGen definitions (intentionally last)
+//===----------------------------------------------------------------------===//
+
+#define GET_OP_CLASSES
+#include "iree/compiler/Dialect/HAL/IR/HALOps.cpp.inc"
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/HAL/IR/HALOps.h b/iree/compiler/Dialect/HAL/IR/HALOps.h
new file mode 100644
index 0000000..cb81be5
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALOps.h
@@ -0,0 +1,43 @@
+// Copyright 2019 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_IR_HALOPS_H_
+#define IREE_COMPILER_DIALECT_HAL_IR_HALOPS_H_
+
+#include <cstdint>
+
+#include "iree/compiler/Dialect/HAL/IR/HALDialect.h"
+#include "iree/compiler/Dialect/HAL/IR/HALTypes.h"
+#include "iree/compiler/Dialect/Traits.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/Module.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/StandardTypes.h"
+#include "mlir/IR/SymbolTable.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+#define GET_OP_CLASSES
+#include "iree/compiler/Dialect/HAL/IR/HALOps.h.inc"
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_HAL_IR_HALOPS_H_
diff --git a/iree/compiler/Dialect/HAL/IR/HALOps.td b/iree/compiler/Dialect/HAL/IR/HALOps.td
new file mode 100644
index 0000000..38c4ec9
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALOps.td
@@ -0,0 +1,118 @@
+// Copyright 2019 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_DIALECT_HAL_OPS
+#define IREE_DIALECT_HAL_OPS
+
+include "iree/compiler/Dialect/HAL/IR/HALBase.td"
+
+//===----------------------------------------------------------------------===//
+// iree::hal::Executable
+//===----------------------------------------------------------------------===//
+
+// TODO(benvanik): executable runtime type.
+
+def HAL_ExecutableOp : HAL_Op<"executable", [
+    IsolatedFromAbove,
+    SingleBlockImplicitTerminator<"IREE::HAL::ExecutableEndOp">,
+    Symbol,
+  ]> {
+  let summary = [{target-specific executable module}];
+  let description = [{
+    An executable module representing a target-specific compiled
+    kernel/shader/etc.
+  }];
+
+  let arguments = (ins
+    StrAttr:$sym_name
+    // TODO(benvanik): entry point types for verification.
+  );
+
+  let regions = (region SizedRegion<1>:$body);
+
+  let skipDefaultBuilders = 1;
+  let builders = [
+    OpBuilder<[{
+      Builder *builder, OperationState &state, StringRef name
+    }]>,
+  ];
+
+  let extraClassDeclaration = [{
+    Block& getBlock() { return body().front(); }
+  }];
+
+  let verifier = [{ return verifyExecutableOp(*this); }];
+}
+
+def HAL_ExecutableEndOp : HAL_Op<"executable_end", [
+    HasParent<"IREE::HAL::ExecutableOp">,
+    Terminator,
+  ]> {
+  let summary = [{terminator pseudo-op for the executable op}];
+  let parser = [{ return parseRegionEndOp(parser, &result); }];
+  let printer = [{ return printRegionEndOp(p, *this); }];
+}
+
+// TODO(benvanik): add HAL_ExecutableSourceOp for auto serialization.
+
+def HAL_ExecutableBinaryOp : HAL_Op<"executable.binary", [
+    IsolatedFromAbove,
+    HasParent<"IREE::HAL::ExecutableOp">,
+    SingleBlockImplicitTerminator<"IREE::HAL::ExecutableBinaryEndOp">,
+  ]> {
+  let summary = [{compiled executable binary data}];
+  let description = [{
+    A compiled executable binary with an optional nested module containing the
+    IR prior to serialization (for debugging).
+  }];
+
+  let arguments = (ins
+    HAL_ExecutableFormatAttr:$format,
+    HAL_ExecutableDataAttr:$data
+    // TODO(benvanik): add compatibility and versioning attributes.
+  );
+
+  let regions = (region SizedRegion<1>:$body);
+
+  let skipDefaultBuilders = 1;
+  let builders = [
+    OpBuilder<[{
+      Builder *builder, OperationState &state, uint32_t format,
+      std::vector<uint8_t> data
+    }]>,
+  ];
+
+  let extraClassDeclaration = [{
+    Block& getBlock() { return body().front(); }
+
+    llvm::Optional<::mlir::ModuleOp> getInnerModule() {
+      auto moduleOps = getBlock().getOps<::mlir::ModuleOp>();
+      if (moduleOps.empty()) return llvm::None;
+      return *moduleOps.begin();
+    }
+  }];
+
+  let verifier = [{ return verifyExecutableBinaryOp(*this); }];
+}
+
+def HAL_ExecutableBinaryEndOp : HAL_Op<"executable.binary_end", [
+    HasParent<"IREE::HAL::ExecutableBinaryOp">,
+    Terminator,
+  ]> {
+  let summary = [{terminator pseudo-op for the executable binary op}];
+  let parser = [{ return parseRegionEndOp(parser, &result); }];
+  let printer = [{ return printRegionEndOp(p, *this); }];
+}
+
+#endif  // IREE_DIALECT_HAL_OPS
diff --git a/iree/compiler/Dialect/HAL/IR/HALTypes.cpp b/iree/compiler/Dialect/HAL/IR/HALTypes.cpp
new file mode 100644
index 0000000..daa2021
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALTypes.cpp
@@ -0,0 +1,32 @@
+// Copyright 2019 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/IR/HALTypes.h"
+
+#include "third_party/llvm/llvm/include/llvm/ADT/StringExtras.h"
+
+// Order matters:
+#include "iree/compiler/Dialect/HAL/IR/HALEnums.cpp.inc"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+// TODO(benvanik): struct types.
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/HAL/IR/HALTypes.h b/iree/compiler/Dialect/HAL/IR/HALTypes.h
new file mode 100644
index 0000000..d7639d8
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/HALTypes.h
@@ -0,0 +1,135 @@
+// Copyright 2019 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_IR_HALTYPES_H_
+#define IREE_COMPILER_DIALECT_HAL_IR_HALTYPES_H_
+
+#include <cstdint>
+
+#include "iree/compiler/Dialect/Types.h"
+#include "mlir/IR/TypeSupport.h"
+#include "mlir/IR/Types.h"
+#include "mlir/Support/LLVM.h"
+#include "third_party/llvm/llvm/include/llvm/ADT/DenseMap.h"
+#include "third_party/llvm/llvm/include/llvm/ADT/DenseMapInfo.h"
+#include "third_party/llvm/llvm/include/llvm/ADT/Optional.h"
+#include "third_party/llvm/llvm/include/llvm/ADT/SmallVector.h"
+#include "third_party/llvm/llvm/include/llvm/ADT/StringSwitch.h"
+
+// Order matters.
+#include "iree/compiler/Dialect/HAL/IR/HALEnums.h.inc"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace HAL {
+
+class AllocatorType : public Type::TypeBase<AllocatorType, Type> {
+ public:
+  using Base::Base;
+  static AllocatorType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Allocator);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Allocator; }
+};
+
+class BufferType : public Type::TypeBase<BufferType, Type> {
+ public:
+  using Base::Base;
+  static BufferType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Buffer);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Buffer; }
+};
+
+class CommandBufferType : public Type::TypeBase<CommandBufferType, Type> {
+ public:
+  using Base::Base;
+  static CommandBufferType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::CommandBuffer);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::CommandBuffer; }
+};
+
+class DeviceType : public Type::TypeBase<DeviceType, Type> {
+ public:
+  using Base::Base;
+  static DeviceType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Device);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Device; }
+};
+
+class EventType : public Type::TypeBase<EventType, Type> {
+ public:
+  using Base::Base;
+  static EventType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Event);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Event; }
+};
+
+class ExecutableType : public Type::TypeBase<ExecutableType, Type> {
+ public:
+  using Base::Base;
+  static ExecutableType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Executable);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Executable; }
+};
+
+class ExecutableCacheType : public Type::TypeBase<ExecutableCacheType, Type> {
+ public:
+  using Base::Base;
+  static ExecutableCacheType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::ExecutableCache);
+  }
+  static bool kindof(unsigned kind) {
+    return kind == TypeKind::ExecutableCache;
+  }
+};
+
+class FenceType : public Type::TypeBase<FenceType, Type> {
+ public:
+  using Base::Base;
+  static FenceType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Fence);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Fence; }
+};
+
+class RingBufferType : public Type::TypeBase<RingBufferType, Type> {
+ public:
+  using Base::Base;
+  static RingBufferType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::RingBuffer);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::RingBuffer; }
+};
+
+class SemaphoreType : public Type::TypeBase<SemaphoreType, Type> {
+ public:
+  using Base::Base;
+  static SemaphoreType get(MLIRContext *context) {
+    return Base::get(context, TypeKind::Semaphore);
+  }
+  static bool kindof(unsigned kind) { return kind == TypeKind::Semaphore; }
+};
+
+}  // namespace HAL
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_HAL_IR_HALTYPES_H_
diff --git a/iree/compiler/Dialect/HAL/IR/test/BUILD b/iree/compiler/Dialect/HAL/IR/test/BUILD
new file mode 100644
index 0000000..beab62e
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/test/BUILD
@@ -0,0 +1,28 @@
+# Copyright 2019 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.
+
+load("//iree:build_defs.bzl", "iree_glob_lit_tests", "iree_setup_lit_package")
+
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+iree_setup_lit_package(
+    data = [
+        "//iree/tools:iree-opt",
+    ],
+)
+
+iree_glob_lit_tests()
diff --git a/iree/compiler/Dialect/HAL/IR/test/executable_ops.mlir b/iree/compiler/Dialect/HAL/IR/test/executable_ops.mlir
new file mode 100644
index 0000000..1782ea0
--- /dev/null
+++ b/iree/compiler/Dialect/HAL/IR/test/executable_ops.mlir
@@ -0,0 +1,57 @@
+// Copyright 2019 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.
+
+// Tests printing and parsing of executable/structural ops.
+
+// RUN: iree-opt -split-input-file %s | iree-opt | FileCheck %s --dump-input=fail
+
+// CHECK-LABEL: @ex
+hal.executable @ex {
+  // CHECK-NEXT: hal.executable.binary
+  hal.executable.binary attributes {
+    // CHECK-SAME: data = dense<1> : vector<128xi8>,
+    data = dense<1> : vector<128xi8>,
+    // CHECK-SAME: format = 1230128453 : i32
+    format = 1230128453 : i32
+  }
+}
+
+// -----
+
+// CHECK-LABEL: @ex_with_source
+hal.executable @ex_with_source {
+  // CHECK-NEXT: hal.executable.binary
+  hal.executable.binary attributes {
+    // CHECK-SAME: data = dense<1> : vector<128xi8>,
+    data = dense<1> : vector<128xi8>,
+    // CHECK-SAME: format = 1230128453 : i32
+    format = 1230128453 : i32
+  } {
+    // CHECK-NEXT: module {
+    module {
+      // CHECK-NEXT: func @dispatch0
+      func @dispatch0(%arg0: memref<4xf32>, %arg1: memref<4xf32>) attributes {
+          iree.executable.export,
+          iree.executable.workload = dense<[4, 1, 1]> : tensor<3xi32>,
+          iree.ordinal = 0 : i32} {
+        %0 = "iree_ll_interp.alloc_heap"() : () -> memref<4xf32>
+        "iree_ll_interp.add_f"(%arg0, %arg0, %0) : (memref<4xf32>, memref<4xf32>, memref<4xf32>) -> ()
+        %1 = "iree_ll_interp.constant"() {value = dense<0> : tensor<1xi64>} : () -> memref<1xi64>
+        %2 = "iree_ll_interp.constant"() {value = dense<4> : tensor<1xi64>} : () -> memref<1xi64>
+        "iree_ll_interp.dynamic_copy"(%0, %1, %arg1, %1, %2) : (memref<4xf32>, memref<1xi64>, memref<4xf32>, memref<1xi64>, memref<1xi64>) -> ()
+        iree.return
+      }
+    }
+  }
+}
diff --git a/iree/compiler/Dialect/Types.h b/iree/compiler/Dialect/Types.h
index 7e88bb0..bd9ab40 100644
--- a/iree/compiler/Dialect/Types.h
+++ b/iree/compiler/Dialect/Types.h
@@ -49,6 +49,7 @@
   Executable,
   ExecutableCache,
   Fence,
+  RingBuffer,
   Semaphore,
 };
 }  // namespace TypeKind
@@ -77,12 +78,15 @@
       case IREE::TypeKind::OpaqueRefObject:
       case IREE::TypeKind::ByteBuffer:
       case IREE::TypeKind::MutableByteBuffer:
+      case HAL::TypeKind::Allocator:
       case HAL::TypeKind::Buffer:
       case HAL::TypeKind::CommandBuffer:
       case HAL::TypeKind::Device:
       case HAL::TypeKind::Event:
       case HAL::TypeKind::Executable:
+      case HAL::TypeKind::ExecutableCache:
       case HAL::TypeKind::Fence:
+      case HAL::TypeKind::RingBuffer:
       case HAL::TypeKind::Semaphore:
       case SEQ::TypeKind::Device:
       case SEQ::TypeKind::Policy:
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index 8e12641..abf8e11 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -35,6 +35,7 @@
         "//iree/compiler/Dialect/Flow/Analysis",
         "//iree/compiler/Dialect/Flow/IR",
         "//iree/compiler/Dialect/Flow/Transforms",
+        "//iree/compiler/Dialect/HAL/IR",
         "//iree/compiler/Dialect/VM/Analysis",
         "//iree/compiler/Dialect/VM/Conversion/StandardToVM",
         "//iree/compiler/Dialect/VM/IR",