Start a Vulkan dialect and define attributes for target environment

To support multiple Vulkan target environments, we need a way to pass
in the configuration of the target environment. Attribute is a pragmatic
mechanism for achieving that purpose, so introducing TargetEnvAttr
for this purpose and created a Vulkan dialect to contain it as we might
gradually collect more Vulkan definitions so it's better to have the
structure set up at the beginning.

The benefits of having an attribute for representing the target environment
are that we can leverage the MLIR parser to parse it and also attach it to
various IR entities to drive conversions at various place. The former avoids
us  from shipping a JSON (or other format) parser in the compiler as long as
one queries the Vulkan environment and dump the information in the format
expected by the TargetEnvAttr. For the latter, we may consider introduce
some corresponding HAL ops so the attribute can drive the scheduling CodeGen.
At the same time, we can transform this attribute into the SPIR-V TargetEnvAttr
and use it to control SPIR-V CodeGen.

PiperOrigin-RevId: 298429559
diff --git a/iree/compiler/Dialect/CMakeLists.txt b/iree/compiler/Dialect/CMakeLists.txt
index fc4f9cf..e081e9a 100644
--- a/iree/compiler/Dialect/CMakeLists.txt
+++ b/iree/compiler/Dialect/CMakeLists.txt
@@ -19,3 +19,4 @@
 add_subdirectory(Shape)
 add_subdirectory(VM)
 add_subdirectory(VMLA)
+add_subdirectory(Vulkan)
diff --git a/iree/compiler/Dialect/IREE/IR/BUILD b/iree/compiler/Dialect/IREE/IR/BUILD
index 5bd982d..11a2287 100644
--- a/iree/compiler/Dialect/IREE/IR/BUILD
+++ b/iree/compiler/Dialect/IREE/IR/BUILD
@@ -35,6 +35,7 @@
         "IREETypes.cpp",
     ],
     hdrs = [
+        "IREEAttributes.h",
         "IREEDialect.h",
         "IREEOps.h",
         "IREEOps.h.inc",
diff --git a/iree/compiler/Dialect/IREE/IR/CMakeLists.txt b/iree/compiler/Dialect/IREE/IR/CMakeLists.txt
index fddf55d..23252fa 100644
--- a/iree/compiler/Dialect/IREE/IR/CMakeLists.txt
+++ b/iree/compiler/Dialect/IREE/IR/CMakeLists.txt
@@ -19,6 +19,7 @@
   NAME
     IR
   HDRS
+    "IREEAttributes.h"
     "IREEDialect.h"
     "IREEOps.h"
     "IREEOps.h.inc"
diff --git a/iree/compiler/Dialect/IREE/IR/IREEAttributes.h b/iree/compiler/Dialect/IREE/IR/IREEAttributes.h
new file mode 100644
index 0000000..0cc7e63
--- /dev/null
+++ b/iree/compiler/Dialect/IREE/IR/IREEAttributes.h
@@ -0,0 +1,42 @@
+// 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_IREE_IR_IREEATTRIBUTES_H_
+#define IREE_COMPILER_DIALECT_IREE_IR_IREEATTRIBUTES_H_
+
+#include "mlir/IR/Attributes.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+
+namespace AttrKind {
+enum Kind {
+  FIRST_VULKAN_ATTR = Attribute::FIRST_IREE_ATTR + 20,
+};
+}  // namespace AttrKind
+
+namespace Vulkan {
+namespace AttrKind {
+enum Kind {
+  TargetEnv = IREE::AttrKind::FIRST_VULKAN_ATTR,
+};
+}  // namespace AttrKind
+}  // namespace Vulkan
+
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_IREE_IR_IREEATTRIBUTES_H_
diff --git a/iree/compiler/Dialect/Vulkan/CMakeLists.txt b/iree/compiler/Dialect/Vulkan/CMakeLists.txt
new file mode 100644
index 0000000..ff45be2
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/CMakeLists.txt
@@ -0,0 +1,15 @@
+# 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.
+
+add_subdirectory(IR)
diff --git a/iree/compiler/Dialect/Vulkan/IR/BUILD b/iree/compiler/Dialect/Vulkan/IR/BUILD
new file mode 100644
index 0000000..dd41492
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/BUILD
@@ -0,0 +1,80 @@
+# 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.
+
+load("//build_tools/bazel:tblgen.bzl", "gentbl")
+
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+filegroup(
+    name = "td_files",
+    srcs = glob(["*.td"]),
+)
+
+cc_library(
+    name = "IR",
+    srcs = [
+        "VulkanAttributes.cpp",
+        "VulkanAttributes.cpp.inc",
+        "VulkanDialect.cpp",
+        "VulkanEnums.cpp.inc",
+        "VulkanTypes.cpp",
+    ],
+    hdrs = [
+        "VulkanAttributes.h",
+        "VulkanAttributes.h.inc",
+        "VulkanDialect.h",
+        "VulkanEnums.h.inc",
+        "VulkanTypes.h",
+    ],
+    deps = [
+        ":VulkanAttrsGen",
+        ":VulkanEnumsGen",
+        "//iree/compiler/Dialect/IREE/IR",
+        "@llvm-project//llvm:support",
+        "@llvm-project//mlir:IR",
+        "@llvm-project//mlir:Support",
+    ],
+    alwayslink = 1,
+)
+
+gentbl(
+    name = "VulkanAttrsGen",
+    tbl_outs = [
+        ("-gen-struct-attr-decls", "VulkanAttributes.h.inc"),
+        ("-gen-struct-attr-defs", "VulkanAttributes.cpp.inc"),
+    ],
+    tblgen = "@llvm-project//mlir:mlir-tblgen",
+    td_file = "VulkanAttributes.td",
+    td_srcs = [
+        ":td_files",
+        "@llvm-project//mlir:OpBaseTdFiles",
+    ],
+)
+
+gentbl(
+    name = "VulkanEnumsGen",
+    tbl_outs = [
+        ("-gen-enum-decls", "VulkanEnums.h.inc"),
+        ("-gen-enum-defs", "VulkanEnums.cpp.inc"),
+    ],
+    tblgen = "@llvm-project//mlir:mlir-tblgen",
+    td_file = "VulkanBase.td",
+    td_srcs = [
+        ":td_files",
+        "@llvm-project//mlir:OpBaseTdFiles",
+    ],
+)
diff --git a/iree/compiler/Dialect/Vulkan/IR/CMakeLists.txt b/iree/compiler/Dialect/Vulkan/IR/CMakeLists.txt
new file mode 100644
index 0000000..09c440a
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/CMakeLists.txt
@@ -0,0 +1,60 @@
+# 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.
+
+add_subdirectory(test)
+
+file(GLOB _GLOB_X_TD CONFIGURE_DEPENDS *.td)
+iree_cc_library(
+  NAME
+    IR
+  HDRS
+    "VulkanAttributes.h"
+    "VulkanAttributes.h.inc"
+    "VulkanDialect.h"
+    "VulkanEnums.h.inc"
+    "VulkanTypes.h"
+  SRCS
+    "VulkanAttributes.cpp"
+    "VulkanAttributes.cpp.inc"
+    "VulkanDialect.cpp"
+    "VulkanEnums.cpp.inc"
+    "VulkanTypes.cpp"
+  DEPS
+    LLVMSupport
+    MLIRIR
+    MLIRSupport
+    iree::compiler::Dialect::IREE::IR
+  ALWAYSLINK
+  PUBLIC
+)
+
+iree_tablegen_library(
+  NAME
+    VulkanAttrsGen
+  TD_FILE
+    "VulkanAttributes.td"
+  OUTS
+    -gen-struct-attr-decls VulkanAttributes.h.inc
+    -gen-struct-attr-defs VulkanAttributes.cpp.inc
+)
+
+iree_tablegen_library(
+  NAME
+    VulkanEnumsGen
+  TD_FILE
+    "VulkanBase.td"
+  OUTS
+    -gen-enum-decls VulkanEnums.h.inc
+    -gen-enum-defs VulkanEnums.cpp.inc
+)
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.cpp b/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.cpp
new file mode 100644
index 0000000..63aba06
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.cpp
@@ -0,0 +1,127 @@
+// 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/Vulkan/IR/VulkanAttributes.h"
+
+#include "mlir/IR/AttributeSupport.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/Identifier.h"
+#include "mlir/IR/Location.h"
+#include "mlir/IR/StandardTypes.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.cpp.inc"
+
+namespace Vulkan {
+
+namespace detail {
+struct TargetEnvAttributeStorage : public AttributeStorage {
+  using KeyTy = std::tuple<Attribute, Attribute, Attribute, Attribute>;
+
+  TargetEnvAttributeStorage(Attribute version, Attribute revision,
+                            Attribute extensions, Attribute core10Properties)
+      : version(version),
+        revision(revision),
+        extensions(extensions),
+        core10Properties(core10Properties) {}
+
+  bool operator==(const KeyTy &key) const {
+    return std::get<0>(key) == version && std::get<1>(key) == revision &&
+           std::get<2>(key) == extensions &&
+           std::get<3>(key) == core10Properties;
+  }
+
+  static TargetEnvAttributeStorage *construct(
+      AttributeStorageAllocator &allocator, const KeyTy &key) {
+    return new (allocator.allocate<TargetEnvAttributeStorage>())
+        TargetEnvAttributeStorage(std::get<0>(key), std::get<1>(key),
+                                  std::get<2>(key), std::get<3>(key));
+  }
+
+  Attribute version;
+  Attribute revision;
+  Attribute extensions;
+  Attribute core10Properties;
+};
+}  // namespace detail
+
+TargetEnvAttr TargetEnvAttr::get(IntegerAttr version, IntegerAttr revision,
+                                 ArrayAttr extensions,
+                                 DictionaryAttr core10Properties) {
+  assert(version && revision && extensions && core10Properties);
+  MLIRContext *context = version.getContext();
+  return Base::get(context, AttrKind::TargetEnv, version, revision, extensions,
+                   core10Properties);
+}
+
+StringRef TargetEnvAttr::getKindName() { return "target_env"; }
+
+Version TargetEnvAttr::getVersion() {
+  return static_cast<Version>(
+      getImpl()->version.cast<IntegerAttr>().getValue().getZExtValue());
+}
+
+unsigned TargetEnvAttr::getRevision() {
+  return getImpl()->revision.cast<IntegerAttr>().getValue().getZExtValue();
+}
+
+TargetEnvAttr::ext_iterator::ext_iterator(ArrayAttr::iterator it)
+    : llvm::mapped_iterator<ArrayAttr::iterator, Extension (*)(Attribute)>(
+          it, [](Attribute attr) {
+            return *symbolizeExtension(attr.cast<StringAttr>().getValue());
+          }) {}
+
+TargetEnvAttr::ext_range TargetEnvAttr::getExtensions() {
+  auto range = getExtensionsAttr().getValue();
+  return {ext_iterator(range.begin()), ext_iterator(range.end())};
+}
+
+ArrayAttr TargetEnvAttr::getExtensionsAttr() {
+  return getImpl()->extensions.cast<ArrayAttr>();
+}
+
+DictionaryAttr TargetEnvAttr::getCore10Properties() {
+  return getImpl()->core10Properties.cast<DictionaryAttr>();
+}
+
+LogicalResult TargetEnvAttr::verifyConstructionInvariants(
+    Location loc, IntegerAttr version, IntegerAttr revision,
+    ArrayAttr extensions, DictionaryAttr core10Properties) {
+  if (!version.getType().isInteger(32))
+    return emitError(loc) << "expected 32-bit integer for version";
+
+  if (!revision.getType().isInteger(32))
+    return emitError(loc) << "expected 32-bit integer for revision";
+
+  if (!llvm::all_of(extensions.getValue(), [](Attribute attr) {
+        if (auto strAttr = attr.dyn_cast<StringAttr>())
+          if (symbolizeExtension(strAttr.getValue())) return true;
+        return false;
+      }))
+    return emitError(loc) << "unknown extension in extension list";
+
+  if (!core10Properties.isa<Core10PropertiesAttr>())
+    return emitError(loc)
+           << "expected vulkan::Core10PropertiesAttr for core10Properties";
+
+  return success();
+}
+
+}  // namespace Vulkan
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.h b/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.h
new file mode 100644
index 0000000..cbe3524
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.h
@@ -0,0 +1,85 @@
+// 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_VULKAN_IR_VULKANATTRIBUTES_H_
+#define IREE_COMPILER_DIALECT_VULKAN_IR_VULKANATTRIBUTES_H_
+
+#include "iree/compiler/Dialect/IREE/IR/IREEAttributes.h"
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanTypes.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.h.inc"
+
+namespace Vulkan {
+
+namespace detail {
+struct TargetEnvAttributeStorage;
+}  // namespace detail
+
+/// An attribute that specifies the target version, supported extensions, and
+/// resource limits. These information describles a Vulkan target environment.
+class TargetEnvAttr
+    : public Attribute::AttrBase<TargetEnvAttr, Attribute,
+                                 detail::TargetEnvAttributeStorage> {
+ public:
+  using Base::Base;
+
+  /// Gets a TargetEnvAttr instance.
+  // TODO(antiagainst): support other physical device core properties, physical
+  // device core features and per-extension features.
+  static TargetEnvAttr get(IntegerAttr version, IntegerAttr revision,
+                           ArrayAttr extensions,
+                           DictionaryAttr core10Properties);
+
+  /// Returns the attribute kind's name (without the 'vk.' prefix).
+  static StringRef getKindName();
+
+  /// Returns the target Vulkan version; e.g., for 1.1.120, it should be V_1_1.
+  Version getVersion();
+
+  /// Returns the target Vulkan revision; e.g., for 1.1.120, it should be 120.
+  unsigned getRevision();
+
+  struct ext_iterator final
+      : public llvm::mapped_iterator<ArrayAttr::iterator,
+                                     Extension (*)(Attribute)> {
+    explicit ext_iterator(ArrayAttr::iterator it);
+  };
+  using ext_range = llvm::iterator_range<ext_iterator>;
+
+  /// Returns the target Vulkan instance and device extensions.
+  ext_range getExtensions();
+  /// Returns the target Vulkan instance and device extensions as an string
+  /// array attribute.
+  ArrayAttr getExtensionsAttr();
+
+  /// Returns the Vulkan 1.0 core properties.
+  DictionaryAttr getCore10Properties();
+
+  static bool kindof(unsigned kind) { return kind == AttrKind::TargetEnv; }
+
+  static LogicalResult verifyConstructionInvariants(
+      Location loc, IntegerAttr version, IntegerAttr revision,
+      ArrayAttr extensions, DictionaryAttr core10Properties);
+};
+
+}  // namespace Vulkan
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_VULKAN_IR_VULKANATTRIBUTES_H_
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.td b/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.td
new file mode 100644
index 0000000..cf37aca
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.td
@@ -0,0 +1,33 @@
+// 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_DIALECT_VULKAN_VULKANATTRIBUTES
+#define IREE_DIALECT_VULKAN_VULKANATTRIBUTES
+
+include "iree/compiler/Dialect/Vulkan/IR/VulkanBase.td"
+
+// TODO(antiagainst): consider auto-generating this file (or part of it) from
+// vk.xml:
+// https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/master/xml/vk.xml
+
+// Core Vulkan 1.0 physical device properties.
+//
+// This corresponds to the `VkPhysicalDeviceProperties` structure:
+// https://renderdoc.org/vkspec_chunked/chap4.html#VkPhysicalDeviceProperties.
+def VK_Core10PropertiesAttr : StructAttr<"Core10PropertiesAttr", VK_Dialect, [
+  StructFieldAttr<"maxComputeWorkGroupInvocations", I32Attr>,
+  StructFieldAttr<"maxComputeWorkGroupSize", I32ElementsAttr>
+]>;
+
+#endif  // IREE_DIALECT_VULKAN_VULKANATTRIBUTES
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanBase.td b/iree/compiler/Dialect/Vulkan/IR/VulkanBase.td
new file mode 100644
index 0000000..ebfd63a
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanBase.td
@@ -0,0 +1,96 @@
+// 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_DIALECT_VULKAN_BASE
+#define IREE_DIALECT_VULKAN_BASE
+
+include "mlir/IR/OpBase.td"
+
+//===----------------------------------------------------------------------===//
+// Vulkan dialect definition
+//===----------------------------------------------------------------------===//
+
+def VK_Dialect : Dialect {
+  let name = "vk";
+  let cppNamespace = "Vulkan";
+
+  let summary = "The Vulkan dialect in IREE";
+  let description = [{
+    Vulkan is a new generation graphics and compute API that provides
+    high-efficiency, cross-platform access to modern GPUs used in a wide
+    variety of devices from PCs and consoles to mobile phones and embedded
+    platforms. See https://www.khronos.org/vulkan for more details regarding
+    Vulkan itself.
+
+    The Vulkan dialect defines common Vulkan concepts in intermediate
+    representation to be amenable to compiler analysis and transformation.
+  }];
+}
+
+//===----------------------------------------------------------------------===//
+// Utility definitions
+//===----------------------------------------------------------------------===//
+
+// A predicate that checks whether `$_self` is a known enum case for the
+// enum class with `name`.
+class VK_IsKnownIntEnumCaseFor<string name> :
+    CPred<"::mlir::iree_compiler::IREE::vulkan::symbolize" # name # "("
+          "$_self.cast<IntegerAttr>().getValue().getZExtValue()).hasValue()">;
+class VK_IsKnownStrEnumCaseFor<string name> :
+    CPred<"::mlir::iree_compiler::IREE::vulkan::symbolize" # name # "("
+          "$_self.cast<StringAttr>().getValue()).hasValue()">;
+
+// Wrapper over base I32EnumAttr to set common fields.
+class VK_I32EnumAttr<string name, string description,
+                      list<I32EnumAttrCase> cases> :
+    I32EnumAttr<name, description, cases> {
+  let predicate = And<[
+    IntegerAttrBase<I32, "">.predicate,
+    VK_IsKnownIntEnumCaseFor<name>,
+  ]>;
+  let cppNamespace = "::mlir::iree_compiler::IREE::Vulkan";
+}
+
+// Wrapper over base StrEnumAttr to set common fields.
+class VK_StrEnumAttr<string name, string description,
+                      list<StrEnumAttrCase> cases> :
+    StrEnumAttr<name, description, cases> {
+  let predicate = And<[
+    StrAttr.predicate,
+    VK_IsKnownStrEnumCaseFor<name>,
+  ]>;
+  let cppNamespace = "::mlir::iree_compiler::IREE::Vulkan";
+}
+
+//===----------------------------------------------------------------------===//
+// Target Environment
+//===----------------------------------------------------------------------===//
+
+def VK_V_1_0 : I32EnumAttrCase<"V_1_0", 0, "v1.0">;
+def VK_V_1_1 : I32EnumAttrCase<"V_1_1", 1, "v1.1">;
+def VK_V_1_2 : I32EnumAttrCase<"V_1_2", 2, "v1.2">;
+
+def VK_VersionAttr : VK_I32EnumAttr<"Version", "valid Vulkan version", [
+    VK_V_1_0, VK_V_1_1, VK_V_1_2]>;
+
+def VK_KHR_spirv_1_4 : StrEnumAttrCase<"VK_KHR_spirv_1_4">;
+def VK_KHR_storage_buffer_storage_class : StrEnumAttrCase<
+    "VK_KHR_storage_buffer_storage_class">;
+
+def VK_ExtensionnAttr :
+    VK_StrEnumAttr<"Extension", "supported Vulkan extension", [
+      VK_KHR_spirv_1_4, VK_KHR_storage_buffer_storage_class
+    ]>;
+
+#endif  // IREE_DIALECT_VULKAN_BASE
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanDialect.cpp b/iree/compiler/Dialect/Vulkan/IR/VulkanDialect.cpp
new file mode 100644
index 0000000..edc9907
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanDialect.cpp
@@ -0,0 +1,188 @@
+// 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/Vulkan/IR/VulkanDialect.h"
+
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanAttributes.h"
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanTypes.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SMLoc.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/DialectImplementation.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace Vulkan {
+
+static DialectRegistration<VulkanDialect> vkDialect;
+
+VulkanDialect::VulkanDialect(MLIRContext *context)
+    : Dialect(getDialectNamespace(), context) {
+  addAttributes<TargetEnvAttr>();
+}
+
+//===----------------------------------------------------------------------===//
+// Attribute Parsing
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+/// Parses a comma-separated list of keywords, invokes `processKeyword` on each
+/// of the parsed keyword, and returns failure if any error occurs.
+ParseResult parseKeywordList(
+    DialectAsmParser &parser,
+    function_ref<LogicalResult(llvm::SMLoc, StringRef)> processKeyword) {
+  if (parser.parseLSquare()) return failure();
+
+  // Special case for empty list.
+  if (succeeded(parser.parseOptionalRSquare())) return success();
+
+  // Keep parsing the keyword and an optional comma following it. If the comma
+  // is successfully parsed, then we have more keywords to parse.
+  do {
+    auto loc = parser.getCurrentLocation();
+    StringRef keyword;
+    if (parser.parseKeyword(&keyword) || failed(processKeyword(loc, keyword)))
+      return failure();
+  } while (succeeded(parser.parseOptionalComma()));
+
+  if (parser.parseRSquare()) return failure();
+
+  return success();
+}
+
+/// Parses a TargetEnvAttr.
+Attribute parseTargetAttr(DialectAsmParser &parser) {
+  if (parser.parseLess()) return {};
+
+  Builder &builder = parser.getBuilder();
+
+  IntegerAttr versionAttr;
+  {
+    auto loc = parser.getCurrentLocation();
+    StringRef version;
+    if (parser.parseKeyword(&version) || parser.parseComma()) return {};
+
+    if (auto versionSymbol = symbolizeVersion(version)) {
+      versionAttr =
+          builder.getI32IntegerAttr(static_cast<uint32_t>(*versionSymbol));
+    } else {
+      parser.emitError(loc, "unknown Vulkan version: ") << version;
+      return {};
+    }
+  }
+
+  IntegerAttr revisionAttr;
+  {
+    unsigned revision = 0;
+    // TODO(antiagainst): it would be nice to parse rN instad of r(N).
+    if (parser.parseKeyword("r") || parser.parseLParen() ||
+        parser.parseInteger(revision) || parser.parseRParen() ||
+        parser.parseComma())
+      return {};
+    revisionAttr = builder.getI32IntegerAttr(revision);
+  }
+
+  ArrayAttr extensionsAttr;
+  {
+    SmallVector<Attribute, 1> extensions;
+    llvm::SMLoc errorloc;
+    StringRef errorKeyword;
+
+    auto processExtension = [&](llvm::SMLoc loc, StringRef extension) {
+      if (symbolizeExtension(extension)) {
+        extensions.push_back(builder.getStringAttr(extension));
+        return success();
+      }
+      return errorloc = loc, errorKeyword = extension, failure();
+    };
+    if (parseKeywordList(parser, processExtension) || parser.parseComma()) {
+      if (!errorKeyword.empty())
+        parser.emitError(errorloc, "unknown Vulkan extension: ")
+            << errorKeyword;
+      return {};
+    }
+
+    extensionsAttr = builder.getArrayAttr(extensions);
+  }
+
+  DictionaryAttr core10PropertiesAttr;
+  {
+    auto loc = parser.getCurrentLocation();
+    if (parser.parseAttribute(core10PropertiesAttr)) return {};
+
+    if (!core10PropertiesAttr.isa<Core10PropertiesAttr>()) {
+      parser.emitError(loc,
+                       "core10Properties must be a "
+                       "vulkan::Core10PropertiesAttr dictionary attribute");
+      return {};
+    }
+  }
+
+  if (parser.parseGreater()) return {};
+
+  return TargetEnvAttr::get(versionAttr, revisionAttr, extensionsAttr,
+                            core10PropertiesAttr);
+}
+}  // anonymous namespace
+
+Attribute VulkanDialect::parseAttribute(DialectAsmParser &parser,
+                                        Type type) const {
+  // Vulkan attributes do not have type.
+  if (type) {
+    parser.emitError(parser.getNameLoc(), "unexpected type");
+    return {};
+  }
+
+  // Parse the kind keyword first.
+  StringRef attrKind;
+  if (parser.parseKeyword(&attrKind)) return {};
+
+  if (attrKind == TargetEnvAttr::getKindName()) return parseTargetAttr(parser);
+
+  parser.emitError(parser.getNameLoc(), "unknown Vulkan attriubte kind: ")
+      << attrKind;
+  return {};
+}
+
+//===----------------------------------------------------------------------===//
+// Attribute Printing
+//===----------------------------------------------------------------------===//
+
+namespace {
+void print(TargetEnvAttr targetEnv, DialectAsmPrinter &printer) {
+  auto &os = printer.getStream();
+  printer << TargetEnvAttr::getKindName() << "<"
+          << stringifyVersion(targetEnv.getVersion()) << ", r("
+          << targetEnv.getRevision() << "), [";
+  interleaveComma(targetEnv.getExtensionsAttr(), os, [&](Attribute attr) {
+    os << attr.cast<StringAttr>().getValue();
+  });
+  printer << "], " << targetEnv.getCore10Properties() << ">";
+}
+}  // anonymous namespace
+
+void VulkanDialect::printAttribute(Attribute attr,
+                                   DialectAsmPrinter &printer) const {
+  if (auto targetEnv = attr.dyn_cast<TargetEnvAttr>())
+    print(targetEnv, printer);
+  else
+    llvm_unreachable("unhandled Vulkan attribute kind");
+}
+
+}  // namespace Vulkan
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanDialect.h b/iree/compiler/Dialect/Vulkan/IR/VulkanDialect.h
new file mode 100644
index 0000000..b77533c
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanDialect.h
@@ -0,0 +1,47 @@
+// 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_VULKAN_IR_VULKANDIALECT_H_
+#define IREE_COMPILER_DIALECT_VULKAN_IR_VULKANDIALECT_H_
+
+#include "mlir/IR/Dialect.h"
+
+namespace mlir {
+namespace iree_compiler {
+namespace IREE {
+namespace Vulkan {
+
+class VulkanDialect : public Dialect {
+ public:
+  explicit VulkanDialect(MLIRContext *context);
+
+  static StringRef getDialectNamespace() { return "vk"; }
+
+  //===--------------------------------------------------------------------===//
+  // Attribute
+  //===--------------------------------------------------------------------===//
+
+  /// Parses an attribute registered to this dialect.
+  Attribute parseAttribute(DialectAsmParser &parser, Type type) const override;
+
+  /// Prints an attribute registered to this dialect.
+  void printAttribute(Attribute, DialectAsmPrinter &printer) const override;
+};
+
+}  // namespace Vulkan
+}  // namespace IREE
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_VULKAN_IR_VULKANDIALECT_H_
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanTypes.cpp b/iree/compiler/Dialect/Vulkan/IR/VulkanTypes.cpp
new file mode 100644
index 0000000..37592b0
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanTypes.cpp
@@ -0,0 +1,17 @@
+// 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/Vulkan/IR/VulkanTypes.h"
+
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanEnums.cpp.inc"
diff --git a/iree/compiler/Dialect/Vulkan/IR/VulkanTypes.h b/iree/compiler/Dialect/Vulkan/IR/VulkanTypes.h
new file mode 100644
index 0000000..7755e48
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/VulkanTypes.h
@@ -0,0 +1,25 @@
+// 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_VULKAN_IR_VULKANTYPES_H_
+#define IREE_COMPILER_DIALECT_VULKAN_IR_VULKANTYPES_H_
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+
+// Order matters.
+#include "iree/compiler/Dialect/Vulkan/IR/VulkanEnums.h.inc"
+
+#endif  // IREE_COMPILER_DIALECT_VULKAN_IR_VULKANTYPES_H_
diff --git a/iree/compiler/Dialect/Vulkan/IR/test/BUILD b/iree/compiler/Dialect/Vulkan/IR/test/BUILD
new file mode 100644
index 0000000..14281d1
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/test/BUILD
@@ -0,0 +1,29 @@
+# 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.
+
+load("//iree:lit_test.bzl", "iree_lit_test_suite")
+
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+iree_lit_test_suite(
+    name = "lit",
+    srcs = glob(["*.mlir"]),
+    data = [
+        "//iree/tools:IreeFileCheck",
+        "//iree/tools:iree-opt",
+    ],
+)
diff --git a/iree/compiler/Dialect/Vulkan/IR/test/CMakeLists.txt b/iree/compiler/Dialect/Vulkan/IR/test/CMakeLists.txt
new file mode 100644
index 0000000..debe338
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/test/CMakeLists.txt
@@ -0,0 +1,24 @@
+# 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.
+
+file(GLOB _GLOB_X_MLIR CONFIGURE_DEPENDS *.mlir)
+iree_lit_test_suite(
+  NAME
+    lit
+  SRCS
+    "${_GLOB_X_MLIR}"
+  DATA
+    iree::tools::IreeFileCheck
+    iree::tools::iree-opt
+)
diff --git a/iree/compiler/Dialect/Vulkan/IR/test/target_env.mlir b/iree/compiler/Dialect/Vulkan/IR/test/target_env.mlir
new file mode 100644
index 0000000..0863bbe
--- /dev/null
+++ b/iree/compiler/Dialect/Vulkan/IR/test/target_env.mlir
@@ -0,0 +1,66 @@
+// Test parsing and printing Vulkan target environment attribute.
+
+// RUN: iree-opt -split-input-file -verify-diagnostics %s | IreeFileCheck %s
+
+"vk_configure_op"() {
+  // CHECK:      #vk.target_env<v1.0, r(0), [], {
+  // CHECK-SAME:   maxComputeWorkGroupInvocations = 128 : i32,
+  // CHECK-SAME:   maxComputeWorkGroupSize = dense<[64, 4, 4]> : vector<3xi32>
+  // CHECK-SAME: }>
+  target_env = #vk.target_env<v1.0, r(0), [], {
+    maxComputeWorkGroupInvocations = 128: i32,
+    maxComputeWorkGroupSize = dense<[64, 4, 4]>: vector<3xi32>
+  }>
+} : () -> ()
+
+
+"vk_configure_op"() {
+  // CHECK:      #vk.target_env<v1.1, r(120), [VK_KHR_spirv_1_4, VK_KHR_storage_buffer_storage_class], {
+  // CHECK-SAME:   maxComputeWorkGroupInvocations = 1024 : i32,
+  // CHECK-SAME:   maxComputeWorkGroupSize = dense<[128, 8, 4]> : vector<3xi32>
+  // CHECK-SAME: }>
+  target_env = #vk.target_env<v1.1, r(120), [VK_KHR_spirv_1_4, VK_KHR_storage_buffer_storage_class], {
+    maxComputeWorkGroupInvocations = 1024: i32,
+    maxComputeWorkGroupSize = dense<[128, 8, 4]>: vector<3xi32>
+  }>
+} : () -> ()
+
+// -----
+
+"unknown_vulkan_version"() {
+  // expected-error @+1 {{unknown Vulkan version: v10.8}}
+  target_env = #vk.target_env<v10.8, r(0), [], {
+    maxComputeWorkGroupInvocations = 128: i32,
+    maxComputeWorkGroupSize = dense<[64, 4, 4]>: vector<3xi32>
+  }>
+} : () -> ()
+
+// -----
+
+"unknown_vulkan_extension"() {
+  // expected-error @+1 {{unknown Vulkan extension: VK_KHR_something}}
+  target_env = #vk.target_env<v1.0, r(10), [VK_KHR_something], {
+    maxComputeWorkGroupInvocations = 128: i32,
+    maxComputeWorkGroupSize = dense<[64, 4, 4]>: vector<3xi32>
+  }>
+} : () -> ()
+
+// -----
+
+"missing_core_1_1_properties_field"() {
+  // expected-error @+1 {{core10Properties must be a vulkan::Core10PropertiesAttr dictionary attribute}}
+  target_env = #vk.target_env<v1.0, r(10), [], {
+    maxComputeWorkGroupInvocations = 128: i32
+  }>
+} : () -> ()
+
+// -----
+
+"unknown_core_1_1_properties_field"() {
+  // expected-error @+1 {{core10Properties must be a vulkan::Core10PropertiesAttr dictionary attribute}}
+  target_env = #vk.target_env<v1.0, r(10), [], {
+    maxComputeWorkGroupInvocations = 128: i32,
+    maxComputeWorkGroupSize = dense<[64, 4, 4]>: vector<3xi32>,
+    moreStuff = 8: i32
+  }>
+} : () -> ()
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index fc6854b..30b6e0b 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -89,6 +89,7 @@
         "//iree/compiler/Dialect/VMLA/Conversion/VMLAToVM",
         "//iree/compiler/Dialect/VMLA/IR",
         "//iree/compiler/Dialect/VMLA/Transforms",
+        "//iree/compiler/Dialect/Vulkan/IR",
         "//iree/compiler/Translation/Interpreter/Transforms",
         "//iree/compiler/Translation:IREEVM",
         "//iree/compiler/Translation/XLAToLinalg",
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index 8474f25..a8b3873 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -181,6 +181,7 @@
       iree::compiler::Dialect::VM::Conversion::StandardToVM
       iree::compiler::Dialect::VM::IR
       iree::compiler::Dialect::VM::Transforms
+      iree::compiler::Dialect::Vulkan::IR
       iree::compiler::Translation::Interpreter::Transforms
       iree::compiler::Translation::IREEVM
       iree::compiler::Translation::SPIRV::LinalgToSPIRV