Hoist buildIREEVMTransformPassPipeline() to its own library and build standalone ireec tool. (#8559)

* Hoist buildIREEVMTransformPassPipeline() to its own library and build standalone ireec tool.

* NFC for iree-translate: we can slim it down in a subsequent patch, but right now, it does exactly what it did before.
* Supplies the ConstEval hook at the very top levels in order to make dependencies a DAG.
* Refactors constant jitting to use buildIREEVMTransformPassPipeline() now that the circular dep is broken.
* Makes IREEVM/CMakeLists.txt generated by bazel_to_cmake:
  * If EMITC is disabled, just generated dummy libraries that do not define IREE_HAVE_EMITC_DIALECT
  * Adds an iree/compiler/Dialect/VM/Target/C:Enabled library which defines IREE_HAVE_EMITC_DIALECT
  * Backs out build graph changes based on emitc enable/disable: now the targets remain no matter what and code can just check the macro
  * Removes the global CMake IREE_HAVE_EMITC_DIALECT copt.
* Adds new ireec tool:
  * Gloms it onto the existing iree_translate_lib which will get renamed to ireec_lib when I'm done (and the existing iree-translate bits that are still needed just inlined into iree-translate-main.cc).
  * Requires an input file (or '-') vs blocking forever.
  * Translation is specified with a new `--output-format=vm-bytecode|c-module|vm-asm` with fallbacks to the old `--iree-mlir-to-vm-c-module` and `--iree-mlir-to-vm-bytecode-module`
  * Defaults to "vm-bytecode".
  * Adds a bit of grouping to CL options for aesthetics.
* Removes the redundant emitError on the module for any failure (for both old and new tool). This is redundant and we now just print a simple compile failed message to errs() in case if there are any lingering bugs where we return failure() but fail to emit a diagnostic. Should be a pretty big QOL improvement.
* A subsequent patch will convert everything to use ireec and downgrade iree-translate to just a serialization testing tool.
diff --git a/build_tools/cmake/iree_copts.cmake b/build_tools/cmake/iree_copts.cmake
index 8a8ae4b..89955ab 100644
--- a/build_tools/cmake/iree_copts.cmake
+++ b/build_tools/cmake/iree_copts.cmake
@@ -416,10 +416,3 @@
   # tools in LLVM.
   iree_get_executable_path(IREE_TABLEGEN_EXE iree-tblgen)
 endif()
-#-------------------------------------------------------------------------------
-# Third party: mlir-emitc
-#-------------------------------------------------------------------------------
-
-if(IREE_ENABLE_EMITC)
-  add_definitions(-DIREE_HAVE_EMITC_DIALECT)
-endif()
diff --git a/iree/compiler/ConstEval/BUILD b/iree/compiler/ConstEval/BUILD
index 9c0c8db..8d46a3a 100644
--- a/iree/compiler/ConstEval/BUILD
+++ b/iree/compiler/ConstEval/BUILD
@@ -54,22 +54,12 @@
         ":PassHeaders",
         ":PassesIncGen",
         ":Runtime",
-        # TODO: Prune.
-        "//iree/compiler/Bindings/Native/Transforms",
-        "//iree/compiler/Dialect/Flow/Transforms",
-        "//iree/compiler/Dialect/HAL/Transforms",
-        "//iree/compiler/Dialect/Stream/Transforms",
-        "//iree/compiler/Dialect/Util/Transforms",
-        "//iree/compiler/Dialect/Util/IR",
-        "//iree/compiler/Dialect/VM/Conversion",
-        "//iree/compiler/Dialect/VM/Conversion/StandardToVM",
-        "//iree/compiler/Dialect/VM/Target/Bytecode",
-        "//iree/compiler/Dialect/VM/Transforms",
+        "//iree/compiler/Pipelines",
         "//iree/compiler/Utils",
         "@llvm-project//llvm:Support",
+        "@llvm-project//mlir:FuncDialect",
         "@llvm-project//mlir:IR",
         "@llvm-project//mlir:Pass",
-        "@llvm-project//mlir:FuncDialect",
     ],
 )
 
diff --git a/iree/compiler/ConstEval/CMakeLists.txt b/iree/compiler/ConstEval/CMakeLists.txt
index 9c0a3e4..4fe7503 100644
--- a/iree/compiler/ConstEval/CMakeLists.txt
+++ b/iree/compiler/ConstEval/CMakeLists.txt
@@ -49,16 +49,7 @@
     MLIRFunc
     MLIRIR
     MLIRPass
-    iree::compiler::Bindings::Native::Transforms
-    iree::compiler::Dialect::Flow::Transforms
-    iree::compiler::Dialect::HAL::Transforms
-    iree::compiler::Dialect::Stream::Transforms
-    iree::compiler::Dialect::Util::IR
-    iree::compiler::Dialect::Util::Transforms
-    iree::compiler::Dialect::VM::Conversion
-    iree::compiler::Dialect::VM::Conversion::StandardToVM
-    iree::compiler::Dialect::VM::Target::Bytecode
-    iree::compiler::Dialect::VM::Transforms
+    iree::compiler::Pipelines
     iree::compiler::Utils
   PUBLIC
 )
diff --git a/iree/compiler/ConstEval/JitGlobals.cpp b/iree/compiler/ConstEval/JitGlobals.cpp
index eda8cac..e455d9d 100644
--- a/iree/compiler/ConstEval/JitGlobals.cpp
+++ b/iree/compiler/ConstEval/JitGlobals.cpp
@@ -4,17 +4,10 @@
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-#include "iree/compiler/Bindings/Native/Transforms/Passes.h"
 #include "iree/compiler/ConstEval/PassDetail.h"
 #include "iree/compiler/ConstEval/Passes.h"
 #include "iree/compiler/ConstEval/Runtime.h"
-#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
-#include "iree/compiler/Dialect/HAL/Transforms/Passes.h"
-#include "iree/compiler/Dialect/Stream/Transforms/Passes.h"
-#include "iree/compiler/Dialect/Util/IR/UtilOps.h"
-#include "iree/compiler/Dialect/Util/Transforms/Passes.h"
-#include "iree/compiler/Dialect/VM/Target/Bytecode/BytecodeModuleTarget.h"
-#include "iree/compiler/Dialect/VM/Transforms/Passes.h"
+#include "iree/compiler/Pipelines/Pipelines.h"
 #include "iree/compiler/Utils/PassUtils.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/Support/Debug.h"
@@ -119,10 +112,13 @@
 // shared.
 // TODO: See if we can make them copyable?
 struct CompileOptions {
-  IREE::Flow::TransformOptions flowOptions;
+  BindingOptions bindingOptions;
+  InputDialectOptions inputOptions;
+  HighLevelOptimizationOptions highLevelOptimizationOptions;
+  SchedulingOptions schedulingOptions;
   IREE::HAL::TargetOptions executableOptions;
-  IREE::Stream::TransformOptions streamOptions;
   IREE::VM::TargetOptions targetOptions;
+  IREEVMPipelineHooks hooks;
 };
 
 struct JitGlobalsPass : public JitGlobalsBase<JitGlobalsPass> {
@@ -130,22 +126,16 @@
       : options(std::make_shared<CompileOptions>()),
         compilePipeline("builtin.module") {
     // Invoke IREE compilation flow.
-    // TODO: Find a better place for this canonical list of passes?
-    // TODO: Something better?
     options->executableOptions.targets.push_back("vmvx");
     options->targetOptions.i64Extension = true;
     options->targetOptions.f32Extension = true;
     options->targetOptions.f64Extension = true;
 
-    IREE::ABI::buildTransformPassPipeline(compilePipeline);
-    IREE::Flow::buildFlowTransformPassPipeline(compilePipeline,
-                                               options->flowOptions);
-    IREE::Stream::buildStreamTransformPassPipeline(compilePipeline,
-                                                   options->streamOptions);
-    IREE::HAL::buildHALTransformPassPipeline(compilePipeline,
-                                             options->executableOptions);
-    IREE::VM::buildVMTransformPassPipeline(compilePipeline,
-                                           options->targetOptions);
+    buildIREEVMTransformPassPipeline(
+        options->bindingOptions, options->inputOptions,
+        options->highLevelOptimizationOptions, options->schedulingOptions,
+        options->executableOptions, options->targetOptions, options->hooks,
+        compilePipeline);
   }
 
   void getDependentDialects(DialectRegistry &registry) const override {
diff --git a/iree/compiler/Dialect/VM/Target/C/BUILD b/iree/compiler/Dialect/VM/Target/C/BUILD
index c3963b0..18e6b73 100644
--- a/iree/compiler/Dialect/VM/Target/C/BUILD
+++ b/iree/compiler/Dialect/VM/Target/C/BUILD
@@ -15,12 +15,33 @@
 iree_cmake_extra_content(
     content = """
 if(NOT "${IREE_ENABLE_EMITC}")
+  # If the real "C" library is enabled, it will define IREE_ENABLE_EMITC,
+  # which can be used for conditionally switching.
+  iree_cc_library(
+    NAME Enabled
+  )
+  iree_cc_library(
+    NAME C
+  )
+  iree_cc_library(
+    NAME TranslateToCpp
+  )
   return()
 endif()
 """,
 )
 
 cc_library(
+    name = "Enabled",
+    defines = [
+        "IREE_HAVE_EMITC_DIALECT",
+    ],
+    deps = [
+        "@llvm-project//mlir:EmitC",
+    ],
+)
+
+cc_library(
     name = "TranslateToCpp",
     srcs = [
         "TranslateToCpp.cpp",
@@ -29,6 +50,7 @@
         "CppEmitter.h",
     ],
     deps = [
+        ":Enabled",
         "@llvm-project//llvm:Support",
         "@llvm-project//mlir:ControlFlowOps",
         "@llvm-project//mlir:EmitC",
@@ -51,6 +73,7 @@
         "TranslationFlags.h",
     ],
     deps = [
+        ":Enabled",
         ":TranslateToCpp",
         "//iree/compiler/Dialect/Util/IR",
         "//iree/compiler/Dialect/Util/Transforms",
diff --git a/iree/compiler/Dialect/VM/Target/C/CMakeLists.txt b/iree/compiler/Dialect/VM/Target/C/CMakeLists.txt
index b5ff5e6..7da6351 100644
--- a/iree/compiler/Dialect/VM/Target/C/CMakeLists.txt
+++ b/iree/compiler/Dialect/VM/Target/C/CMakeLists.txt
@@ -9,6 +9,17 @@
 ################################################################################
 
 if(NOT "${IREE_ENABLE_EMITC}")
+  # If the real "C" library is enabled, it will define IREE_ENABLE_EMITC,
+  # which can be used for conditionally switching.
+  iree_cc_library(
+    NAME Enabled
+  )
+  iree_cc_library(
+    NAME C
+  )
+  iree_cc_library(
+    NAME TranslateToCpp
+  )
   return()
 endif()
 
@@ -16,12 +27,23 @@
 
 iree_cc_library(
   NAME
+    Enabled
+  DEPS
+    MLIREmitC
+  DEFINES
+    "IREE_HAVE_EMITC_DIALECT"
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
     TranslateToCpp
   HDRS
     "CppEmitter.h"
   SRCS
     "TranslateToCpp.cpp"
   DEPS
+    ::Enabled
     LLVMSupport
     MLIRControlFlow
     MLIREmitC
@@ -43,6 +65,7 @@
     "TranslationFlags.cpp"
     "TranslationRegistration.cpp"
   DEPS
+    ::Enabled
     ::TranslateToCpp
     LLVMSupport
     MLIRIR
diff --git a/iree/compiler/Pipelines/BUILD b/iree/compiler/Pipelines/BUILD
new file mode 100644
index 0000000..0007b07
--- /dev/null
+++ b/iree/compiler/Pipelines/BUILD
@@ -0,0 +1,51 @@
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+package(
+    default_visibility = ["//visibility:public"],
+    features = ["layering_check"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+cc_library(
+    name = "Options",
+    srcs = ["Options.cpp"],
+    hdrs = ["Options.h"],
+    deps = [
+        "//iree/compiler/Utils",
+    ],
+)
+
+cc_library(
+    name = "Pipelines",
+    srcs = [
+        "Pipelines.cpp",
+    ],
+    hdrs = [
+        "Pipelines.h",
+    ],
+    deps = [
+        ":Options",
+        "//iree/compiler/Bindings/Native/Transforms",
+        "//iree/compiler/Bindings/TFLite/Transforms",
+        "//iree/compiler/Dialect/Flow/Transforms",
+        "//iree/compiler/Dialect/HAL/Conversion/HALToVM",
+        "//iree/compiler/Dialect/HAL/Transforms",
+        "//iree/compiler/Dialect/Stream/Transforms",
+        "//iree/compiler/Dialect/Util/Transforms",
+        "//iree/compiler/Dialect/VM/Conversion",
+        "//iree/compiler/Dialect/VM/Conversion/StandardToVM",
+        "//iree/compiler/Dialect/VM/Target/Bytecode",
+        "//iree/compiler/Dialect/VM/Transforms",
+        "//iree/compiler/InputConversion/Common",
+        "//iree/compiler/InputConversion/MHLO",
+        "//iree/compiler/InputConversion/TOSA",
+        "@llvm-project//llvm:Support",
+        "@llvm-project//mlir:IR",
+        "@llvm-project//mlir:Pass",
+        "@llvm-project//mlir:Support",
+    ],
+)
diff --git a/iree/compiler/Pipelines/CMakeLists.txt b/iree/compiler/Pipelines/CMakeLists.txt
new file mode 100644
index 0000000..1885ff0
--- /dev/null
+++ b/iree/compiler/Pipelines/CMakeLists.txt
@@ -0,0 +1,55 @@
+################################################################################
+# Autogenerated by build_tools/bazel_to_cmake/bazel_to_cmake.py from           #
+# iree/compiler/Pipelines/BUILD                                                #
+#                                                                              #
+# Use iree_cmake_extra_content from iree/build_defs.oss.bzl to add arbitrary   #
+# CMake-only content.                                                          #
+#                                                                              #
+# To disable autogeneration for this file entirely, delete this header.        #
+################################################################################
+
+iree_add_all_subdirs()
+
+iree_cc_library(
+  NAME
+    Options
+  HDRS
+    "Options.h"
+  SRCS
+    "Options.cpp"
+  DEPS
+    iree::compiler::Utils
+  PUBLIC
+)
+
+iree_cc_library(
+  NAME
+    Pipelines
+  HDRS
+    "Pipelines.h"
+  SRCS
+    "Pipelines.cpp"
+  DEPS
+    ::Options
+    LLVMSupport
+    MLIRIR
+    MLIRPass
+    MLIRSupport
+    iree::compiler::Bindings::Native::Transforms
+    iree::compiler::Bindings::TFLite::Transforms
+    iree::compiler::Dialect::Flow::Transforms
+    iree::compiler::Dialect::HAL::Conversion::HALToVM
+    iree::compiler::Dialect::HAL::Transforms
+    iree::compiler::Dialect::Stream::Transforms
+    iree::compiler::Dialect::Util::Transforms
+    iree::compiler::Dialect::VM::Conversion
+    iree::compiler::Dialect::VM::Conversion::StandardToVM
+    iree::compiler::Dialect::VM::Target::Bytecode
+    iree::compiler::Dialect::VM::Transforms
+    iree::compiler::InputConversion::Common
+    iree::compiler::InputConversion::MHLO
+    iree::compiler::InputConversion::TOSA
+  PUBLIC
+)
+
+### BAZEL_TO_CMAKE_PRESERVES_ALL_CONTENT_BELOW_THIS_LINE ###
diff --git a/iree/compiler/Pipelines/Options.cpp b/iree/compiler/Pipelines/Options.cpp
new file mode 100644
index 0000000..56c09c8
--- /dev/null
+++ b/iree/compiler/Pipelines/Options.cpp
@@ -0,0 +1,97 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "iree/compiler/Pipelines/Options.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+void BindingOptions::bindOptions(OptionsBinder &binder) {
+  static llvm::cl::OptionCategory bindingOptionsCategory(
+      "IREE translation binding support options.");
+
+  binder.opt<bool>(
+      "iree-native-bindings-support", native,
+      llvm::cl::desc(
+          "Include runtime support for native IREE ABI-compatible bindings."),
+      llvm::cl::cat(bindingOptionsCategory));
+  binder.opt<bool>("iree-tflite-bindings-support", tflite,
+                   llvm::cl::desc("Include runtime support for the IREE TFLite "
+                                  "compatibility bindings."),
+                   llvm::cl::cat(bindingOptionsCategory));
+}
+
+void InputDialectOptions::bindOptions(OptionsBinder &binder) {
+  static llvm::cl::OptionCategory inputDialectOptions(
+      "IREE options for controlling the input transformations to apply.");
+
+  binder.opt<InputDialectOptions::Type>(
+      "iree-input-type", type,
+      llvm::cl::desc("Specifies the input program representation."),
+      llvm::cl::values(
+          clEnumValN(InputDialectOptions::Type::none, "none",
+                     "No input dialect transformation."),
+          clEnumValN(InputDialectOptions::Type::tosa, "tosa",
+                     "Legalize from TOSA ops."),
+          clEnumValN(InputDialectOptions::Type::mhlo, "mhlo",
+                     "Legalize from MHLO ops."),
+          clEnumValN(
+              InputDialectOptions::Type::xla, "xla",
+              "Legalize from MHLO ops (with XLA cleanup preprocessing).")),
+      llvm::cl::cat(inputDialectOptions));
+}
+
+void HighLevelOptimizationOptions::bindOptions(OptionsBinder &binder) {
+  static llvm::cl::OptionCategory category(
+      "IREE options for controlling high level optimizations.");
+
+  binder.opt<bool>(
+      "iree-opt-const-eval", constEval,
+      llvm::cl::desc("Enables eager evaluation of constants using the full "
+                     "compiler and runtime."),
+      llvm::cl::cat(category));
+  binder.opt<bool>(
+      "iree-opt-const-expr-hoisting", constExprHoisting,
+      llvm::cl::desc(
+          "Hoists the results of latent constant expressions into immutable "
+          "global initializers for evaluation at program load."),
+      llvm::cl::cat(category));
+  binder.opt<bool>(
+      "iree-opt-numeric-precision-reduction", numericPrecisionReduction,
+      llvm::cl::desc(
+          "Reduces numeric precision to lower bit depths where possible."),
+      llvm::cl::cat(category));
+  binder.opt<bool>("iree-opt-strip-assertions", stripAssertions,
+                   llvm::cl::desc("Strips debug assertions after any useful "
+                                  "information has been extracted."),
+                   llvm::cl::cat(category));
+}
+
+void SchedulingOptions::bindOptions(OptionsBinder &binder) {
+  static llvm::cl::OptionCategory category(
+      "IREE options for controlling host/device scheduling.");
+
+  binder.opt<DumpOutputFormat>(
+      "iree-scheduling-dump-statistics-format", dumpStatisticsFormat,
+      llvm::cl::desc("Dumps statistics in the specified output format."),
+      llvm::cl::cat(category),
+      llvm::cl::values(
+          clEnumValN(DumpOutputFormat::Pretty, "pretty",
+                     "Human-readable pretty printed output."),
+          clEnumValN(DumpOutputFormat::Verbose, "verbose",
+                     "Pretty printed output with additional IR."),
+          clEnumValN(DumpOutputFormat::CSV, "csv", "Comma separated values."),
+          clEnumValN(DumpOutputFormat::JSON, "json",
+                     "JSON output with structures for data exchange")));
+  binder.opt<std::string>("iree-scheduling-dump-statistics-file",
+                          dumpStatisticsFile,
+                          llvm::cl::desc("File path to write statistics to; or "
+                                         "`` for stderr or `-` for stdout."),
+                          llvm::cl::cat(category));
+}
+
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Pipelines/Options.h b/iree/compiler/Pipelines/Options.h
new file mode 100644
index 0000000..4648d49
--- /dev/null
+++ b/iree/compiler/Pipelines/Options.h
@@ -0,0 +1,104 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef IREE_COMPILER_PIPELINES_OPTIONS_H_
+#define IREE_COMPILER_PIPELINES_OPTIONS_H_
+
+#include "iree/compiler/Utils/OptionUtils.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+struct BindingOptions {
+  // Whether to include runtime support functions for the IREE native ABI.
+  bool native = true;
+  // Whether to include runtime support functions required for the IREE TFLite
+  // API compatibility bindings.
+  bool tflite = false;
+
+  void bindOptions(OptionsBinder &binder);
+  using FromFlags = OptionsFromFlags<BindingOptions>;
+};
+
+// The transformation to apply to the input prior to main compiler execution.
+// These input pipelines are purposefully primitive and mainly focused on
+// test case/reproducers as opposed to anything that should be coming from
+// a user. For user/framework level interfacing, a dedicated importer likely
+// needs to be created in order to represent whole-module level framework
+// quirks. These are just about the ops in the functions.
+struct InputDialectOptions {
+  enum class Type {
+    // Applies no input transformation. Only supported core and extension ops
+    // are supported.
+    none,
+    // Legalizes input defined over TOSA ops.
+    tosa,
+    // Legalizes input defined over MHLO ops.
+    mhlo,
+    // Special case of 'mhlo' legalization which also performs some XLA
+    // cleanup activities.
+    xla,
+  };
+  Type type = Type::none;
+
+  void bindOptions(OptionsBinder &binder);
+  using FromFlags = OptionsFromFlags<InputDialectOptions>;
+};
+
+// Options controlling high level optimizations.
+struct HighLevelOptimizationOptions {
+  // Enables const-expr hoisting into globals.
+  bool constExprHoisting = false;
+
+  // Enables recursive evaluation of immutable globals using the compiler
+  // and runtime.
+  bool constEval = false;
+
+  // Optimizations to reduce numeric precision where it is safe to do so.
+  bool numericPrecisionReduction = false;
+
+  // Strips debug assertions after any useful information has been extracted.
+  bool stripAssertions = false;
+
+  void bindOptions(OptionsBinder &binder);
+  using FromFlags = OptionsFromFlags<HighLevelOptimizationOptions>;
+};
+
+// Options controlling scheduling across host/device.
+struct SchedulingOptions {
+  // TODO(benvanik): find a way to share this with
+  // Stream/Transforms/PassDetail.h w/o circular deps.
+  // Defines the output format of a dump pass.
+  enum class DumpOutputFormat {
+    // Dumping disabled.
+    None = 0,
+    // Human-readable pretty printing.
+    Pretty = 1,
+    // Pretty printing with additional information that can result in large
+    // dumps.
+    Verbose = 2,
+    // Comma separated values for throwing into Sheets.
+    CSV = 3,
+    // JSON format for better structure and data exchange.
+    JSON = 4,
+  };
+  // Enables and specifies the the format for a stream statistics dump.
+  DumpOutputFormat dumpStatisticsFormat = DumpOutputFormat::None;
+  // File path to write statistics to; or `` for stderr or `-` for stdout.
+  std::string dumpStatisticsFile = "";
+
+  // TODO(benvanik): favor size/speed/etc for partitioning.
+  // TODO(benvanik): execution model to optimize for (unified/discrete memory,
+  //                 single/multiple processors, etc).
+
+  void bindOptions(OptionsBinder &binder);
+  using FromFlags = OptionsFromFlags<SchedulingOptions>;
+};
+
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_PIPELINES_OPTIONS_H_
diff --git a/iree/compiler/Pipelines/Pipelines.cpp b/iree/compiler/Pipelines/Pipelines.cpp
new file mode 100644
index 0000000..14fd07a
--- /dev/null
+++ b/iree/compiler/Pipelines/Pipelines.cpp
@@ -0,0 +1,97 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "iree/compiler/Pipelines/Pipelines.h"
+
+#include "iree/compiler/Bindings/Native/Transforms/Passes.h"
+#include "iree/compiler/Bindings/TFLite/Transforms/Passes.h"
+#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
+#include "iree/compiler/Dialect/HAL/Transforms/Passes.h"
+#include "iree/compiler/Dialect/Stream/Transforms/Passes.h"
+#include "iree/compiler/Dialect/Util/Transforms/Passes.h"
+#include "iree/compiler/Dialect/VM/Transforms/Passes.h"
+#include "iree/compiler/InputConversion/Common/Passes.h"
+#include "iree/compiler/InputConversion/MHLO/Passes.h"
+#include "iree/compiler/InputConversion/TOSA/Passes.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+void buildIREEVMTransformPassPipeline(
+    BindingOptions bindingOptions, InputDialectOptions inputOptions,
+    HighLevelOptimizationOptions highLevelOptimizationOptions,
+    SchedulingOptions schedulingOptions,
+    IREE::HAL::TargetOptions executableOptions,
+    IREE::VM::TargetOptions targetOptions, IREEVMPipelineHooks &hooks,
+    OpPassManager &passManager) {
+  // Input pipelines can result in changes to the exported functions and types
+  // and must run before generating bindings.
+  // After input processing, there should only be IREE legal types in
+  // signatures.
+  switch (inputOptions.type) {
+    case InputDialectOptions::Type::none:
+      break;
+    case InputDialectOptions::Type::tosa:
+      buildTOSAInputConversionPassPipeline(passManager);
+      break;
+    case InputDialectOptions::Type::mhlo:
+      MHLO::buildMHLOInputConversionPassPipeline(passManager);
+      break;
+    case InputDialectOptions::Type::xla:
+      MHLO::buildXLACleanupPassPipeline(passManager);
+      MHLO::buildMHLOInputConversionPassPipeline(passManager);
+      break;
+  }
+  buildCommonInputConversionPassPipeline(passManager);
+
+  // Now that inputs are legalized, generate wrapper for entry functions.
+  if (bindingOptions.native) {
+    IREE::ABI::buildTransformPassPipeline(passManager);
+  }
+  if (bindingOptions.tflite) {
+    IREE::TFLite::buildTransformPassPipeline(passManager);
+  }
+
+  IREE::Flow::TransformOptions flowOptions;
+  flowOptions.constExprHoisting =
+      highLevelOptimizationOptions.constExprHoisting;
+  flowOptions.numericPrecisionReduction =
+      highLevelOptimizationOptions.numericPrecisionReduction;
+
+  // Enable const-eval via hook. For debug builds, we assert if enabled without
+  // a hook. For release, we just silently skip enabling const-eval.
+  if (highLevelOptimizationOptions.constEval) {
+    assert(hooks.buildConstEvalPassPipelineCallback &&
+           "if const-eval is enabled the buildConstEvalPassPipelineCallback "
+           "hook must be enabled");
+  }
+  if (highLevelOptimizationOptions.constEval &&
+      hooks.buildConstEvalPassPipelineCallback) {
+    flowOptions.buildConstEvalPassPipeline =
+        hooks.buildConstEvalPassPipelineCallback;
+  }
+
+  if (highLevelOptimizationOptions.stripAssertions) {
+    // Strip std.assert & co after we perform optimizations; prior to this we
+    // may use the assertions to derive information during analysis.
+    passManager.addPass(IREE::Util::createStripDebugOpsPass());
+  }
+
+  IREE::Stream::TransformOptions streamOptions;
+  // TODO(benvanik): find a way to share the enums w/o circular deps.
+  streamOptions.dumpStatisticsFormat =
+      (IREE::Stream::DumpOutputFormat)schedulingOptions.dumpStatisticsFormat;
+  streamOptions.dumpStatisticsFile = schedulingOptions.dumpStatisticsFile;
+
+  IREE::Flow::buildFlowTransformPassPipeline(passManager, flowOptions);
+  IREE::Stream::buildStreamTransformPassPipeline(passManager, streamOptions);
+  IREE::HAL::buildHALTransformPassPipeline(passManager, executableOptions);
+  IREE::VM::buildVMTransformPassPipeline(passManager, targetOptions);
+  passManager.addPass(IREE::Util::createDropCompilerHintsPass());
+}
+
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Pipelines/Pipelines.h b/iree/compiler/Pipelines/Pipelines.h
new file mode 100644
index 0000000..b958286
--- /dev/null
+++ b/iree/compiler/Pipelines/Pipelines.h
@@ -0,0 +1,44 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef IREE_COMPILER_PIPELINES_PIPELINES_H_
+#define IREE_COMPILER_PIPELINES_PIPELINES_H_
+
+#include "iree/compiler/Dialect/HAL/Target/TargetRegistry.h"
+#include "iree/compiler/Dialect/VM/Conversion/TargetOptions.h"
+#include "iree/compiler/Dialect/VM/Target/Bytecode/BytecodeModuleTarget.h"
+#include "iree/compiler/Pipelines/Options.h"
+#include "mlir/Pass/PassManager.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+// Hooks for injecting behavior into the IREEVM pipeline. Since these are not
+// derived from CLI options, we maintain them as a separate struct.
+struct IREEVMPipelineHooks {
+  // If the HighLevelOptimizationOptions::constEval option is true, then
+  // this callback must be set to populate a pass manager to perform
+  // constant eval. It typically just adds a ConstEval::createJitGlobalsPass()
+  // pass. It must be injected like this to avoid circular dependencies from
+  // the constant evaluator, which needs to recursively invoke these
+  // pipelines.
+  std::function<void(OpPassManager &)> buildConstEvalPassPipelineCallback;
+};
+
+// Builds a pass pipeline to perform end-to-end compilation from a
+// supported MLIR-based input to the IREE vm dialect.
+void buildIREEVMTransformPassPipeline(
+    BindingOptions bindingOptions, InputDialectOptions inputOptions,
+    HighLevelOptimizationOptions highLevelOptimizationOptions,
+    SchedulingOptions schedulingOptions,
+    IREE::HAL::TargetOptions executableOptions,
+    IREE::VM::TargetOptions targetOptions, IREEVMPipelineHooks &hooks,
+    OpPassManager &passManager);
+
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_PIPELINES_PIPELINES_H_
diff --git a/iree/compiler/Pipelines/README.md b/iree/compiler/Pipelines/README.md
new file mode 100644
index 0000000..5096c4a
--- /dev/null
+++ b/iree/compiler/Pipelines/README.md
@@ -0,0 +1,5 @@
+# IREE Compiler Top-Level Pipelines
+
+This directory defines top-level compiler pipelines and tools integrations.
+It roughly depends on "everything" and is used to construct both CLI compiler
+tools and APIs.
diff --git a/iree/compiler/Translation/BUILD b/iree/compiler/Translation/BUILD
index 39fa7ee..246e24b 100644
--- a/iree/compiler/Translation/BUILD
+++ b/iree/compiler/Translation/BUILD
@@ -30,33 +30,15 @@
     name = "IREEVM",
     srcs = ["IREEVM.cpp"],
     hdrs = ["IREEVM.h"],
-    defines = [
-        "IREE_HAVE_EMITC_DIALECT",
-    ],
     deps = [
-        "//iree/compiler/Bindings/Native/Transforms",
-        "//iree/compiler/Bindings/TFLite/Transforms",
         "//iree/compiler/ConstEval",
         "//iree/compiler/Dialect/Flow/IR",
-        "//iree/compiler/Dialect/Flow/Transforms",
-        "//iree/compiler/Dialect/HAL/Conversion/HALToVM",
         "//iree/compiler/Dialect/HAL/Target",
-        "//iree/compiler/Dialect/HAL/Transforms",
-        "//iree/compiler/Dialect/Stream/Transforms",
-        "//iree/compiler/Dialect/Util/Transforms",
-        "//iree/compiler/Dialect/VM/Conversion",
-        "//iree/compiler/Dialect/VM/Conversion/StandardToVM",
-        "//iree/compiler/Dialect/VM/Target/Bytecode",
         "//iree/compiler/Dialect/VM/Target/C",
-        "//iree/compiler/Dialect/VM/Transforms",
-        "//iree/compiler/InputConversion/Common",
-        "//iree/compiler/InputConversion/MHLO",
-        "//iree/compiler/InputConversion/TOSA",
+        "//iree/compiler/Pipelines",
+        "//iree/compiler/Pipelines:Options",
         "//iree/compiler/Utils",
-        "@llvm-project//llvm:Support",
-        "@llvm-project//mlir:IR",
         "@llvm-project//mlir:Pass",
-        "@llvm-project//mlir:Support",
         "@llvm-project//mlir:Translation",
     ],
 )
diff --git a/iree/compiler/Translation/CMakeLists.txt b/iree/compiler/Translation/CMakeLists.txt
index 5ce302b..8c8aab5 100644
--- a/iree/compiler/Translation/CMakeLists.txt
+++ b/iree/compiler/Translation/CMakeLists.txt
@@ -1,18 +1,15 @@
-# Copyright 2019 The IREE Authors
-#
-# Licensed under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+################################################################################
+# Autogenerated by build_tools/bazel_to_cmake/bazel_to_cmake.py from           #
+# iree/compiler/Translation/BUILD                                              #
+#                                                                              #
+# Use iree_cmake_extra_content from iree/build_defs.oss.bzl to add arbitrary   #
+# CMake-only content.                                                          #
+#                                                                              #
+# To disable autogeneration for this file entirely, delete this header.        #
+################################################################################
 
 iree_add_all_subdirs()
 
-if(IREE_ENABLE_EMITC)
-  set(IREE_VM_CONDITIONAL_TARGETS
-    iree::compiler::Dialect::VM::Target::C
-  )
-endif()
-
-
 iree_cc_library(
   NAME
     HALExecutable
@@ -40,28 +37,16 @@
   SRCS
     "IREEVM.cpp"
   DEPS
-    LLVMSupport
-    MLIRIR
     MLIRPass
-    MLIRSupport
     MLIRTranslateLib
-    iree::compiler::Bindings::Native::Transforms
-    iree::compiler::Bindings::TFLite::Transforms
     iree::compiler::ConstEval
     iree::compiler::Dialect::Flow::IR
-    iree::compiler::Dialect::Flow::Transforms
-    iree::compiler::Dialect::HAL::Conversion::HALToVM
     iree::compiler::Dialect::HAL::Target
-    iree::compiler::Dialect::HAL::Transforms
-    iree::compiler::Dialect::Stream::Transforms
-    iree::compiler::Dialect::Util::Transforms
-    iree::compiler::Dialect::VM::Conversion
-    iree::compiler::Dialect::VM::Conversion::StandardToVM
-    iree::compiler::Dialect::VM::Target::Bytecode
-    iree::compiler::Dialect::VM::Transforms
-    iree::compiler::InputConversion::MHLO
-    iree::compiler::InputConversion::TOSA
+    iree::compiler::Dialect::VM::Target::C
+    iree::compiler::Pipelines
+    iree::compiler::Pipelines::Options
     iree::compiler::Utils
-    ${IREE_VM_CONDITIONAL_TARGETS}
   PUBLIC
 )
+
+### BAZEL_TO_CMAKE_PRESERVES_ALL_CONTENT_BELOW_THIS_LINE ###
diff --git a/iree/compiler/Translation/IREEVM.cpp b/iree/compiler/Translation/IREEVM.cpp
index 8e0bf84..b31abd8 100644
--- a/iree/compiler/Translation/IREEVM.cpp
+++ b/iree/compiler/Translation/IREEVM.cpp
@@ -6,20 +6,10 @@
 
 #include "iree/compiler/Translation/IREEVM.h"
 
-#include "iree/compiler/Bindings/Native/Transforms/Passes.h"
-#include "iree/compiler/Bindings/TFLite/Transforms/Passes.h"
 #include "iree/compiler/ConstEval/Passes.h"
-#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
-#include "iree/compiler/Dialect/HAL/Transforms/Passes.h"
-#include "iree/compiler/Dialect/Stream/Transforms/Passes.h"
-#include "iree/compiler/Dialect/Util/Transforms/Passes.h"
-#include "iree/compiler/Dialect/VM/Transforms/Passes.h"
-#include "iree/compiler/InputConversion/Common/Passes.h"
-#include "iree/compiler/InputConversion/MHLO/Passes.h"
-#include "iree/compiler/InputConversion/TOSA/Passes.h"
+#include "iree/compiler/Pipelines/Pipelines.h"
 #include "iree/compiler/Utils/PassUtils.h"
 #include "iree/compiler/Utils/TracingUtils.h"
-#include "mlir/IR/BuiltinOps.h"
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Tools/mlir-translate/Translation.h"
 
@@ -31,153 +21,16 @@
 namespace mlir {
 namespace iree_compiler {
 
-void BindingOptions::bindOptions(OptionsBinder &binder) {
-  static llvm::cl::OptionCategory bindingOptionsCategory(
-      "IREE translation binding support options.");
+namespace {
 
-  binder.opt<bool>(
-      "iree-native-bindings-support", native,
-      llvm::cl::desc(
-          "Include runtime support for native IREE ABI-compatible bindings."),
-      llvm::cl::cat(bindingOptionsCategory));
-  binder.opt<bool>("iree-tflite-bindings-support", tflite,
-                   llvm::cl::desc("Include runtime support for the IREE TFLite "
-                                  "compatibility bindings."),
-                   llvm::cl::cat(bindingOptionsCategory));
+IREEVMPipelineHooks &getHooks() {
+  static IREEVMPipelineHooks hooks = {
+      // buildConstEvalPassPipelineCallback =
+      [](OpPassManager &pm) { pm.addPass(ConstEval::createJitGlobalsPass()); }};
+  return hooks;
 }
 
-void InputDialectOptions::bindOptions(OptionsBinder &binder) {
-  static llvm::cl::OptionCategory inputDialectOptions(
-      "IREE options for controlling the input transformations to apply.");
-
-  binder.opt<InputDialectOptions::Type>(
-      "iree-input-type", type,
-      llvm::cl::desc("Specifies the input program representation."),
-      llvm::cl::values(
-          clEnumValN(InputDialectOptions::Type::none, "none",
-                     "No input dialect transformation."),
-          clEnumValN(InputDialectOptions::Type::tosa, "tosa",
-                     "Legalize from TOSA ops."),
-          clEnumValN(InputDialectOptions::Type::mhlo, "mhlo",
-                     "Legalize from MHLO ops."),
-          clEnumValN(
-              InputDialectOptions::Type::xla, "xla",
-              "Legalize from MHLO ops (with XLA cleanup preprocessing).")),
-      llvm::cl::cat(inputDialectOptions));
-}
-
-void HighLevelOptimizationOptions::bindOptions(OptionsBinder &binder) {
-  static llvm::cl::OptionCategory category(
-      "IREE options for controlling high level optimizations.");
-
-  binder.opt<bool>(
-      "iree-opt-const-eval", constEval,
-      llvm::cl::desc("Enables eager evaluation of constants using the full "
-                     "compiler and runtime."),
-      llvm::cl::cat(category));
-  binder.opt<bool>(
-      "iree-opt-const-expr-hoisting", constExprHoisting,
-      llvm::cl::desc(
-          "Hoists the results of latent constant expressions into immutable "
-          "global initializers for evaluation at program load."),
-      llvm::cl::cat(category));
-  binder.opt<bool>(
-      "iree-opt-numeric-precision-reduction", numericPrecisionReduction,
-      llvm::cl::desc(
-          "Reduces numeric precision to lower bit depths where possible."),
-      llvm::cl::cat(category));
-  binder.opt<bool>("iree-opt-strip-assertions", stripAssertions,
-                   llvm::cl::desc("Strips debug assertions after any useful "
-                                  "information has been extracted."),
-                   llvm::cl::cat(category));
-}
-
-void SchedulingOptions::bindOptions(OptionsBinder &binder) {
-  static llvm::cl::OptionCategory category(
-      "IREE options for controlling host/device scheduling.");
-
-  binder.opt<DumpOutputFormat>(
-      "iree-scheduling-dump-statistics-format", dumpStatisticsFormat,
-      llvm::cl::desc("Dumps statistics in the specified output format."),
-      llvm::cl::cat(category),
-      llvm::cl::values(
-          clEnumValN(DumpOutputFormat::Pretty, "pretty",
-                     "Human-readable pretty printed output."),
-          clEnumValN(DumpOutputFormat::Verbose, "verbose",
-                     "Pretty printed output with additional IR."),
-          clEnumValN(DumpOutputFormat::CSV, "csv", "Comma separated values."),
-          clEnumValN(DumpOutputFormat::JSON, "json",
-                     "JSON output with structures for data exchange")));
-  binder.opt<std::string>("iree-scheduling-dump-statistics-file",
-                          dumpStatisticsFile,
-                          llvm::cl::desc("File path to write statistics to; or "
-                                         "`` for stderr or `-` for stdout."),
-                          llvm::cl::cat(category));
-}
-
-void buildIREEVMTransformPassPipeline(
-    BindingOptions bindingOptions, InputDialectOptions inputOptions,
-    HighLevelOptimizationOptions highLevelOptimizationOptions,
-    SchedulingOptions schedulingOptions,
-    IREE::HAL::TargetOptions executableOptions,
-    IREE::VM::TargetOptions targetOptions, OpPassManager &passManager) {
-  // Input pipelines can result in changes to the exported functions and types
-  // and must run before generating bindings.
-  // After input processing, there should only be IREE legal types in
-  // signatures.
-  switch (inputOptions.type) {
-    case InputDialectOptions::Type::none:
-      break;
-    case InputDialectOptions::Type::tosa:
-      buildTOSAInputConversionPassPipeline(passManager);
-      break;
-    case InputDialectOptions::Type::mhlo:
-      MHLO::buildMHLOInputConversionPassPipeline(passManager);
-      break;
-    case InputDialectOptions::Type::xla:
-      MHLO::buildXLACleanupPassPipeline(passManager);
-      MHLO::buildMHLOInputConversionPassPipeline(passManager);
-      break;
-  }
-  buildCommonInputConversionPassPipeline(passManager);
-
-  // Now that inputs are legalized, generate wrapper for entry functions.
-  if (bindingOptions.native) {
-    IREE::ABI::buildTransformPassPipeline(passManager);
-  }
-  if (bindingOptions.tflite) {
-    IREE::TFLite::buildTransformPassPipeline(passManager);
-  }
-
-  IREE::Flow::TransformOptions flowOptions;
-  flowOptions.constExprHoisting =
-      highLevelOptimizationOptions.constExprHoisting;
-  if (highLevelOptimizationOptions.constEval) {
-    flowOptions.buildConstEvalPassPipeline = [](OpPassManager &passManager) {
-      passManager.addPass(ConstEval::createJitGlobalsPass());
-    };
-  }
-  flowOptions.numericPrecisionReduction =
-      highLevelOptimizationOptions.numericPrecisionReduction;
-
-  if (highLevelOptimizationOptions.stripAssertions) {
-    // Strip std.assert & co after we perform optimizations; prior to this we
-    // may use the assertions to derive information during analysis.
-    passManager.addPass(IREE::Util::createStripDebugOpsPass());
-  }
-
-  IREE::Stream::TransformOptions streamOptions;
-  // TODO(benvanik): find a way to share the enums w/o circular deps.
-  streamOptions.dumpStatisticsFormat =
-      (IREE::Stream::DumpOutputFormat)schedulingOptions.dumpStatisticsFormat;
-  streamOptions.dumpStatisticsFile = schedulingOptions.dumpStatisticsFile;
-
-  IREE::Flow::buildFlowTransformPassPipeline(passManager, flowOptions);
-  IREE::Stream::buildStreamTransformPassPipeline(passManager, streamOptions);
-  IREE::HAL::buildHALTransformPassPipeline(passManager, executableOptions);
-  IREE::VM::buildVMTransformPassPipeline(passManager, targetOptions);
-  passManager.addPass(IREE::Util::createDropCompilerHintsPass());
-}
+}  // namespace
 
 void buildDefaultIREEVMTransformPassPipeline(OpPassManager &passManager) {
   buildIREEVMTransformPassPipeline(
@@ -185,7 +38,7 @@
       HighLevelOptimizationOptions::FromFlags::get(),
       SchedulingOptions::FromFlags::get(),
       IREE::HAL::TargetOptions::FromFlags::get(),
-      IREE::VM::TargetOptions::FromFlags::get(), passManager);
+      IREE::VM::TargetOptions::FromFlags::get(), getHooks(), passManager);
 }
 
 void registerIREEVMTransformPassPipeline() {
@@ -211,11 +64,13 @@
   mlir::applyPassManagerCLOptions(passManager);
   mlir::applyDefaultTimingPassManagerCLOptions(passManager);
   passManager.addInstrumentation(std::make_unique<PassTracing>());
-  buildIREEVMTransformPassPipeline(
-      bindingOptions, inputOptions, highLevelOptimizationOptions,
-      schedulingOptions, executableOptions, targetOptions, passManager);
+  buildIREEVMTransformPassPipeline(bindingOptions, inputOptions,
+                                   highLevelOptimizationOptions,
+                                   schedulingOptions, executableOptions,
+                                   targetOptions, getHooks(), passManager);
   if (failed(passManager.run(moduleOp))) {
-    return moduleOp.emitError() << "conversion from source -> vm failed";
+    llvm::errs() << "compilation from source to vm failed\n";
+    return failure();
   }
   return success();
 }
diff --git a/iree/compiler/Translation/IREEVM.h b/iree/compiler/Translation/IREEVM.h
index 4f9608f..ab19f05 100644
--- a/iree/compiler/Translation/IREEVM.h
+++ b/iree/compiler/Translation/IREEVM.h
@@ -10,6 +10,7 @@
 #include "iree/compiler/Dialect/HAL/Target/TargetRegistry.h"
 #include "iree/compiler/Dialect/VM/Conversion/TargetOptions.h"
 #include "iree/compiler/Dialect/VM/Target/Bytecode/BytecodeModuleTarget.h"
+#include "iree/compiler/Pipelines/Options.h"
 #include "iree/compiler/Utils/OptionUtils.h"
 #include "llvm/Support/raw_ostream.h"
 #include "mlir/IR/BuiltinOps.h"
@@ -19,108 +20,9 @@
 namespace mlir {
 namespace iree_compiler {
 
-// TODO(#3817): move all of this code to the iree-compile driver/API.
-// Breaking this up such that for development iree-opt runs all passes/pipelines
-// and iree-translate strictly does the VM dialect to bytecode/emitc files will
-// match upstream better, and then our own iree-compile C API/binary will do the
-// whole end-to-end with options for bindings/targets/etc.
-struct BindingOptions {
-  // Whether to include runtime support functions for the IREE native ABI.
-  bool native = true;
-  // Whether to include runtime support functions required for the IREE TFLite
-  // API compatibility bindings.
-  bool tflite = false;
-
-  void bindOptions(OptionsBinder &binder);
-  using FromFlags = OptionsFromFlags<BindingOptions>;
-};
-
-// The transformation to apply to the input prior to main compiler execution.
-// These input pipelines are purposefully primitive and mainly focused on
-// test case/reproducers as opposed to anything that should be coming from
-// a user. For user/framework level interfacing, a dedicated importer likely
-// needs to be created in order to represent whole-module level framework
-// quirks. These are just about the ops in the functions.
-struct InputDialectOptions {
-  enum class Type {
-    // Applies no input transformation. Only supported core and extension ops
-    // are supported.
-    none,
-    // Legalizes input defined over TOSA ops.
-    tosa,
-    // Legalizes input defined over MHLO ops.
-    mhlo,
-    // Special case of 'mhlo' legalization which also performs some XLA
-    // cleanup activities.
-    xla,
-  };
-  Type type = Type::none;
-
-  void bindOptions(OptionsBinder &binder);
-  using FromFlags = OptionsFromFlags<InputDialectOptions>;
-};
-
-// Options controlling high level optimizations.
-struct HighLevelOptimizationOptions {
-  // Enables const-expr hoisting into globals.
-  bool constExprHoisting = false;
-
-  // Enables recursive evaluation of immutable globals using the compiler
-  // and runtime.
-  bool constEval = false;
-
-  // Optimizations to reduce numeric precision where it is safe to do so.
-  bool numericPrecisionReduction = false;
-
-  // Strips debug assertions after any useful information has been extracted.
-  bool stripAssertions = false;
-
-  void bindOptions(OptionsBinder &binder);
-  using FromFlags = OptionsFromFlags<HighLevelOptimizationOptions>;
-};
-
-// Options controlling scheduling across host/device.
-struct SchedulingOptions {
-  // TODO(benvanik): find a way to share this with
-  // Stream/Transforms/PassDetail.h w/o circular deps.
-  // Defines the output format of a dump pass.
-  enum class DumpOutputFormat {
-    // Dumping disabled.
-    None = 0,
-    // Human-readable pretty printing.
-    Pretty = 1,
-    // Pretty printing with additional information that can result in large
-    // dumps.
-    Verbose = 2,
-    // Comma separated values for throwing into Sheets.
-    CSV = 3,
-    // JSON format for better structure and data exchange.
-    JSON = 4,
-  };
-  // Enables and specifies the the format for a stream statistics dump.
-  DumpOutputFormat dumpStatisticsFormat = DumpOutputFormat::None;
-  // File path to write statistics to; or `` for stderr or `-` for stdout.
-  std::string dumpStatisticsFile = "";
-
-  // TODO(benvanik): favor size/speed/etc for partitioning.
-  // TODO(benvanik): execution model to optimize for (unified/discrete memory,
-  //                 single/multiple processors, etc).
-
-  void bindOptions(OptionsBinder &binder);
-  using FromFlags = OptionsFromFlags<SchedulingOptions>;
-};
-
 // Builds the translation pipeline with defaults.
 void buildDefaultIREEVMTransformPassPipeline(OpPassManager &passManager);
 
-// Builds the translation pipeline with explicit options.
-void buildIREEVMTransformPassPipeline(
-    BindingOptions bindingOptions, InputDialectOptions inputOptions,
-    HighLevelOptimizationOptions highLevelOptimizationOptions,
-    SchedulingOptions schedulingOptions,
-    IREE::HAL::TargetOptions executableOptions,
-    IREE::VM::TargetOptions targetOptions, OpPassManager &passManager);
-
 // Registration hooks.
 void registerIREEVMTransformPassPipeline();
 void registerIREEVMTranslation();
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index ed0414c..6c4b3b2 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -131,10 +131,8 @@
         "init_mlir_dialects.h",
         "init_mlir_passes.h",
     ],
-    defines = [
-        "IREE_HAVE_EMITC_DIALECT",
-    ],
     deps = [
+        "//iree/compiler/Dialect/VM/Target/C:Enabled",
         "@llvm-project//mlir:Affine",
         "@llvm-project//mlir:AffineTransforms",
         "@llvm-project//mlir:ArmNeon",
@@ -381,7 +379,10 @@
 
 cc_library(
     name = "iree_translate_lib",
-    srcs = ["iree_translate_lib.cc"],
+    srcs = [
+        "iree_translate_lib.cc",
+        "ireec_lib.cc",
+    ],
     hdrs = ["iree_translate_lib.h"],
     deps = [
         ":init_compiler_modules",
@@ -392,14 +393,19 @@
         ":init_translations",
         ":init_xla_dialects",
         "//iree/compiler/Codegen",
+        "//iree/compiler/ConstEval",
         "//iree/compiler/Dialect/VM/Target:init_targets",
         "//iree/compiler/Dialect/VM/Target/Bytecode",
+        "//iree/compiler/Dialect/VM/Target/C",
+        "//iree/compiler/Pipelines",
         "//iree/compiler/Translation:HALExecutable",
         "//iree/compiler/Translation:IREEVM",
+        "//iree/compiler/Utils",
         "@llvm-project//llvm:Support",
         "@llvm-project//mlir:ArmNeonToLLVMIRTranslation",
         "@llvm-project//mlir:IR",
         "@llvm-project//mlir:LLVMToLLVMIRTranslation",
+        "@llvm-project//mlir:Parser",
         "@llvm-project//mlir:Pass",
         "@llvm-project//mlir:SCFTransforms",
         "@llvm-project//mlir:Support",
@@ -416,3 +422,12 @@
         ":iree_translate_lib",
     ],
 )
+
+cc_binary(
+    name = "ireec",
+    srcs = ["ireec-main.cc"],
+    tags = ["hostonly"],
+    deps = [
+        ":iree_translate_lib",
+    ],
+)
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index 45a47c7..fa8e3bb 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -59,12 +59,6 @@
   list(APPEND IREE_COMPILER_TARGET_COPTS "-DIREE_HAVE_ROCM_TARGET")
 endif()
 
-if(IREE_ENABLE_EMITC)
-  set(IREE_EMITC_CONDITIONAL_DEP
-    MLIREmitC
-  )
-endif()
-
 iree_cc_binary(
   NAME
     iree-benchmark-module
@@ -264,6 +258,9 @@
       "init_mlir_dialects.h"
       "init_mlir_passes.h"
     DEPS
+      # Sets IREE_HAVE_EMITC_DIALECT and transitively depends on MLIREmitC
+      # if enabled.
+      iree::compiler::Dialect::VM::Target::C::Enabled
       MLIRAffine
       MLIRAffineTransforms
       MLIRArmNeon
@@ -293,7 +290,6 @@
       MLIRTosaTransforms
       MLIRTransforms
       MLIRVector
-      ${IREE_EMITC_CONDITIONAL_DEP}
     PUBLIC
   )
 
@@ -380,6 +376,7 @@
     HDRS
       "iree_translate_lib.h"
     SRCS
+      "ireec_lib.cc"
       "iree_translate_lib.cc"
     DEPS
       ::init_compiler_modules
@@ -393,15 +390,20 @@
       MLIRArmNeonToLLVMIRTranslation
       MLIRLLVMToLLVMIRTranslation
       MLIRSCFTransforms
+      MLIRParser
       MLIRPass
       MLIRSupport
       MLIRTargetLLVMIRExport
       MLIRTranslateLib
       iree::compiler::Codegen::Codegen
+      iree::compiler::ConstEval
       iree::compiler::Dialect::VM::Target::Bytecode
       iree::compiler::Dialect::VM::Target::init_targets
+      iree::compiler::Dialect::VM::Target::C
+      iree::compiler::Pipelines
       iree::compiler::Translation::HALExecutable
       iree::compiler::Translation::IREEVM
+      iree::compiler::Utils
     PUBLIC
   )
 
@@ -419,6 +421,20 @@
 
   iree_cc_binary(
     NAME
+      ireec
+    SRCS
+      "ireec-main.cc"
+    DEPS
+      ::iree_translate_lib
+    DATA
+      ${IREE_LLD_TARGET}
+    HOSTONLY
+    # TODO: Enable when ready. Excluded for now to save build time for folks.
+    EXCLUDE_FROM_ALL
+  )
+
+  iree_cc_binary(
+    NAME
       iree-opt
     DEPS
       ::iree_opt_main
diff --git a/iree/tools/iree_translate_lib.cc b/iree/tools/iree_translate_lib.cc
index 0c8c768..9c9a3b2 100644
--- a/iree/tools/iree_translate_lib.cc
+++ b/iree/tools/iree_translate_lib.cc
@@ -40,6 +40,8 @@
 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
 #include "mlir/Tools/mlir-translate/Translation.h"
 
+// TODO: Once we are switched to runIreecMain, this can be slimmed down
+// substantially, since it will just be about testing actual translations.
 int mlir::iree_compiler::runIreeTranslateMain(int argc, char **argv) {
   llvm::InitLLVM y(argc, argv);
   mlir::DialectRegistry registry;
diff --git a/iree/tools/iree_translate_lib.h b/iree/tools/iree_translate_lib.h
index 572e03a..d964d2e 100644
--- a/iree/tools/iree_translate_lib.h
+++ b/iree/tools/iree_translate_lib.h
@@ -12,6 +12,12 @@
 
 int runIreeTranslateMain(int argc, char **argv);
 
+// NOTE: We are transitioning from the main compiler being based on
+// the MLIR translation library (i.e. iree-translate) to a dedicated tool
+// called ireec. When this is done, the above should go away and this file
+// should be renamed to ireec_lib.h.
+int runIreecMain(int argc, char **argv);
+
 }  // namespace iree_compiler
 }  // namespace mlir
 
diff --git a/iree/tools/ireec-main.cc b/iree/tools/ireec-main.cc
new file mode 100644
index 0000000..ec65906
--- /dev/null
+++ b/iree/tools/ireec-main.cc
@@ -0,0 +1,11 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "iree/tools/iree_translate_lib.h"
+
+int main(int argc, char **argv) {
+  return mlir::iree_compiler::runIreecMain(argc, argv);
+}
diff --git a/iree/tools/ireec_lib.cc b/iree/tools/ireec_lib.cc
new file mode 100644
index 0000000..0ef5b78
--- /dev/null
+++ b/iree/tools/ireec_lib.cc
@@ -0,0 +1,251 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include "iree/compiler/ConstEval/Passes.h"
+#include "iree/compiler/Dialect/VM/Target/init_targets.h"
+#include "iree/compiler/Pipelines/Pipelines.h"
+#include "iree/compiler/Utils/PassUtils.h"
+#include "iree/compiler/Utils/TracingUtils.h"
+#include "iree/tools/init_compiler_modules.h"
+#include "iree/tools/init_iree_dialects.h"
+#include "iree/tools/init_mlir_dialects.h"
+#include "iree/tools/init_passes.h"
+#include "iree/tools/init_targets.h"
+#include "iree/tools/init_xla_dialects.h"
+#include "iree/tools/iree_translate_lib.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include "mlir/IR/AsmState.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/Verifier.h"
+#include "mlir/Parser/Parser.h"
+#include "mlir/Pass/PassManager.h"
+#include "mlir/Support/FileUtilities.h"
+#include "mlir/Support/LogicalResult.h"
+#include "mlir/Support/Timing.h"
+#include "mlir/Support/ToolUtilities.h"
+#include "mlir/Tools/mlir-translate/Translation.h"
+
+#ifdef IREE_HAVE_EMITC_DIALECT
+#include "iree/compiler/Dialect/VM/Target/C/CModuleTarget.h"
+#include "iree/compiler/Dialect/VM/Target/C/TranslationFlags.h"
+#endif  // IREE_HAVE_EMITC_DIALECT
+
+namespace mlir {
+namespace iree_compiler {
+
+namespace {
+
+enum class OutputFormat {
+  none,
+  vm_asm,
+  vm_bytecode,
+  vm_c,
+};
+
+IREEVMPipelineHooks &getHooks() {
+  static IREEVMPipelineHooks hooks = {
+      // buildConstEvalPassPipelineCallback =
+      [](OpPassManager &pm) { pm.addPass(ConstEval::createJitGlobalsPass()); }};
+  return hooks;
+}
+
+}  // namespace
+
+}  // namespace iree_compiler
+}  // namespace mlir
+
+int mlir::iree_compiler::runIreecMain(int argc, char **argv) {
+  llvm::InitLLVM y(argc, argv);
+  mlir::DialectRegistry registry;
+  static llvm::cl::OptionCategory mainOptions("IREE Main Options");
+
+  mlir::registerMlirDialects(registry);
+  // TODO: Make this conditional?
+  mlir::registerXLADialects(registry);
+  mlir::iree_compiler::registerAllPasses();
+  mlir::iree_compiler::registerIreeDialects(registry);
+  mlir::iree_compiler::registerIreeCompilerModuleDialects(registry);
+  mlir::iree_compiler::registerHALTargetBackends();
+  mlir::iree_compiler::registerVMTargets();
+
+  // Register MLIRContext command-line options like
+  // -mlir-print-op-on-diagnostic.
+  mlir::registerMLIRContextCLOptions();
+  // Register assembly printer command-line options like
+  // -mlir-print-op-generic.
+  mlir::registerAsmPrinterCLOptions();
+  // Register pass manager command-line options like -print-ir-*.
+  mlir::registerPassManagerCLOptions();
+  mlir::registerDefaultTimingManagerCLOptions();
+
+  // Flag options structs (must resolve prior to CLI parsing).
+  auto &bindingOptions = BindingOptions::FromFlags::get();
+  auto &inputOptions = InputDialectOptions::FromFlags::get();
+  auto &highLevelOptimizationOptions =
+      HighLevelOptimizationOptions::FromFlags::get();
+  auto &schedulingOptions = SchedulingOptions::FromFlags::get();
+  auto &halTargetOptions = IREE::HAL::TargetOptions::FromFlags::get();
+  auto &vmTargetOptions = IREE::VM::TargetOptions::FromFlags::get();
+  auto &bytecodeTargetOptions =
+      IREE::VM::BytecodeTargetOptions::FromFlags::get();
+
+  // General command line flags.
+  llvm::cl::opt<std::string> inputFilename(
+      llvm::cl::Positional, llvm::cl::desc("<input file or '-' for stdin>"),
+      llvm::cl::Required, llvm::cl::cat(mainOptions));
+
+  llvm::cl::opt<std::string> outputFilename(
+      "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
+      llvm::cl::init("-"), llvm::cl::cat(mainOptions));
+
+  // The output format flag is the master control for what we do with the
+  // in-memory compiled form.
+  llvm::cl::opt<OutputFormat> outputFormat(
+      "output-format", llvm::cl::desc("Format of compiled output"),
+      llvm::cl::values(
+          clEnumValN(OutputFormat::vm_bytecode, "vm-bytecode",
+                     "IREE VM Bytecode (default)"),
+#ifdef IREE_HAVE_EMITC_DIALECT
+          clEnumValN(OutputFormat::vm_c, "vm-c", "C source module"),
+#endif
+          clEnumValN(OutputFormat::vm_asm, "vm-asm", "IREE VM MLIR Assembly")),
+      llvm::cl::init(OutputFormat::none), llvm::cl::cat(mainOptions));
+
+  llvm::cl::opt<bool> legacyTranslateToCModule(
+      "iree-mlir-to-vm-c-module",
+      llvm::cl::desc("Alias for --output-format=c-module (deprecated)"),
+      llvm::cl::init(false));
+  llvm::cl::opt<bool> legacyTranslateToVMBytecodeModule(
+      "iree-mlir-to-vm-bytecode-module",
+      llvm::cl::desc("Alias for --output-format=vm-bytecode (deprecated)"),
+      llvm::cl::init(false));
+
+  // Misc options.
+  llvm::cl::opt<bool> splitInputFile(
+      "split-input-file",
+      llvm::cl::desc("Split the input file into pieces and "
+                     "process each chunk independently"),
+      llvm::cl::init(false));
+
+// Optional output formats.
+#ifdef IREE_HAVE_EMITC_DIALECT
+  auto cTargetOptions = IREE::VM::getCTargetOptionsFromFlags();
+#endif
+
+  llvm::cl::ParseCommandLineOptions(argc, argv, "IREE compilation driver\n");
+
+  // Post-process and select the correct outputFormat.
+  if (legacyTranslateToCModule) {
+    if (outputFormat != OutputFormat::none) {
+      llvm::errs()
+          << "Cannot specify --output-format= and --iree-mlir-to-vm-c-module\n";
+      return 1;
+    }
+    outputFormat = OutputFormat::vm_c;
+  }
+  if (legacyTranslateToVMBytecodeModule) {
+    if (outputFormat != OutputFormat::none) {
+      llvm::errs() << "Cannot specify --output-format= and "
+                      "--iree-mlir-to-vm-bytecode-module\n";
+      return 1;
+    }
+    outputFormat = OutputFormat::vm_bytecode;
+  }
+
+  // Defualt output format.
+  if (outputFormat == OutputFormat::none) {
+    outputFormat = OutputFormat::vm_bytecode;
+  }
+
+  std::string errorMessage;
+  auto input = mlir::openInputFile(inputFilename, &errorMessage);
+  if (!input) {
+    llvm::errs() << errorMessage << "\n";
+    return 1;
+  }
+
+  auto output = mlir::openOutputFile(outputFilename, &errorMessage);
+  if (!output) {
+    llvm::errs() << errorMessage << "\n";
+    return 1;
+  }
+
+  /// Processes the memory buffer with a new MLIRContext.
+  auto processBuffer = [&](std::unique_ptr<llvm::MemoryBuffer> ownedBuffer,
+                           llvm::raw_ostream &os) -> LogicalResult {
+    mlir::MLIRContext context;
+    context.allowUnregisteredDialects();
+    context.appendDialectRegistry(registry);
+    llvm::SourceMgr sourceMgr;
+    sourceMgr.AddNewSourceBuffer(std::move(ownedBuffer), llvm::SMLoc());
+    mlir::SourceMgrDiagnosticHandler diagHandler(sourceMgr, &context);
+
+    // Parse source.
+    auto module = parseSourceFile<ModuleOp>(sourceMgr, &context);
+    if (!module || failed(verify(*module))) {
+      return failure();
+    }
+
+    // Main compilation pipeline.
+    PassManager passManager(&context);
+    mlir::applyPassManagerCLOptions(passManager);
+    mlir::applyDefaultTimingPassManagerCLOptions(passManager);
+    passManager.addInstrumentation(std::make_unique<PassTracing>());
+    buildIREEVMTransformPassPipeline(bindingOptions, inputOptions,
+                                     highLevelOptimizationOptions,
+                                     schedulingOptions, halTargetOptions,
+                                     vmTargetOptions, getHooks(), passManager);
+    if (failed(passManager.run(module.get()))) {
+      llvm::errs() << "compilation from source to vm failed\n";
+      return failure();
+    }
+
+    // Switch based on output format.
+    switch (outputFormat) {
+      case OutputFormat::vm_asm:
+        os << module.get();
+        return success();
+      case OutputFormat::vm_bytecode:
+        return translateModuleToBytecode(module.get(), bytecodeTargetOptions,
+                                         os);
+#ifdef IREE_HAVE_EMITC_DIALECT
+      case OutputFormat::vm_c:
+        return mlir::iree_compiler::IREE::VM::translateModuleToC(
+            module.get(), cTargetOptions, os);
+#endif
+      default:
+        llvm::errs() << "INTERNAL ERROR: Unknown output format\n";
+        return failure();
+    }
+
+    return failure();
+  };
+
+  if (splitInputFile) {
+    if (failed(mlir::splitAndProcessBuffer(std::move(input), processBuffer,
+                                           output->os())))
+      return 1;
+  } else {
+    if (failed(processBuffer(std::move(input), output->os()))) return 1;
+  }
+
+  output->keep();
+  return 0;
+}
diff --git a/llvm-external-projects/iree-compiler-api/BUILD.bazel b/llvm-external-projects/iree-compiler-api/BUILD.bazel
index f103ced..98ff213 100644
--- a/llvm-external-projects/iree-compiler-api/BUILD.bazel
+++ b/llvm-external-projects/iree-compiler-api/BUILD.bazel
@@ -64,11 +64,12 @@
     ],
     includes = ["include"],
     deps = [
+        "//iree/compiler/ConstEval",
         "//iree/compiler/Dialect/VM/IR",
         "//iree/compiler/Dialect/VM/Target/Bytecode",
         "//iree/compiler/InputConversion/MHLO",
         "//iree/compiler/InputConversion/TOSA",
-        "//iree/compiler/Translation:IREEVM",
+        "//iree/compiler/Pipelines",
         "//iree/compiler/Utils",
         "//iree/tools:init_targets",
         "//iree/tools:iree_translate_lib",
diff --git a/llvm-external-projects/iree-compiler-api/lib/CAPI/CMakeLists.txt b/llvm-external-projects/iree-compiler-api/lib/CAPI/CMakeLists.txt
index 4226ead..1b4d785 100644
--- a/llvm-external-projects/iree-compiler-api/lib/CAPI/CMakeLists.txt
+++ b/llvm-external-projects/iree-compiler-api/lib/CAPI/CMakeLists.txt
@@ -25,11 +25,12 @@
     Support
   LINK_LIBS PUBLIC
     MLIRIR
+    iree::compiler::ConstEval
     iree::compiler::InputConversion::MHLO::MHLO
     iree::compiler::InputConversion::TOSA::TOSA
     iree::compiler::Dialect::VM::IR::IR
     iree::compiler::Dialect::VM::Target::Bytecode::Bytecode
-    iree::compiler::Translation::IREEVM
+    iree::compiler::Pipelines
 
     # All HAL Targets.
     iree::tools::init_targets
diff --git a/llvm-external-projects/iree-compiler-api/lib/CAPI/Compiler.cpp b/llvm-external-projects/iree-compiler-api/lib/CAPI/Compiler.cpp
index 756c04a..b783580 100644
--- a/llvm-external-projects/iree-compiler-api/lib/CAPI/Compiler.cpp
+++ b/llvm-external-projects/iree-compiler-api/lib/CAPI/Compiler.cpp
@@ -6,11 +6,12 @@
 
 #include "iree-compiler-c/Compiler.h"
 
+#include "iree/compiler/ConstEval/Passes.h"
 #include "iree/compiler/Dialect/VM/IR/VMOps.h"
 #include "iree/compiler/Dialect/VM/Target/Bytecode/BytecodeModuleTarget.h"
 #include "iree/compiler/InputConversion/MHLO/Passes.h"
 #include "iree/compiler/InputConversion/TOSA/Passes.h"
-#include "iree/compiler/Translation/IREEVM.h"
+#include "iree/compiler/Pipelines/Pipelines.h"
 #include "iree/compiler/Utils/OptionUtils.h"
 #include "iree/tools/init_targets.h"
 #include "mlir/CAPI/IR.h"
@@ -133,10 +134,13 @@
                                          MlirOpPassManager passManager) {
   auto *optionsCpp = unwrap(options);
   auto *passManagerCpp = unwrap(passManager);
+  IREEVMPipelineHooks hooks = {
+      // buildConstEvalPassPipelineCallback =
+      [](OpPassManager &pm) { pm.addPass(ConstEval::createJitGlobalsPass()); }};
   buildIREEVMTransformPassPipeline(
       optionsCpp->bindingOptions, optionsCpp->inputDialectOptions,
       optionsCpp->highLevelOptimizationOptions, optionsCpp->schedulingOptions,
-      optionsCpp->halTargetOptions, optionsCpp->vmTargetOptions,
+      optionsCpp->halTargetOptions, optionsCpp->vmTargetOptions, hooks,
       *passManagerCpp);
 }