Adding --emit-mlir-bytecode flag to iree-compile. (#14710)

Allows for emitting mlirbc files instead of textual ones when using the
--compile-to= or --output-format=vm-asm flags.
diff --git a/compiler/src/iree/compiler/Tools/iree_compile_lib.cc b/compiler/src/iree/compiler/Tools/iree_compile_lib.cc
index baaca1a..39e41b1 100644
--- a/compiler/src/iree/compiler/Tools/iree_compile_lib.cc
+++ b/compiler/src/iree/compiler/Tools/iree_compile_lib.cc
@@ -43,6 +43,20 @@
   hal_executable,
 };
 
+struct BytecodeVersionParser : public llvm::cl::parser<std::optional<int64_t>> {
+  BytecodeVersionParser(llvm::cl::Option &O)
+      : llvm::cl::parser<std::optional<int64_t>>(O) {}
+  bool parse(llvm::cl::Option &O, StringRef /*argName*/, StringRef arg,
+             std::optional<int64_t> &v) {
+    long long w;
+    if (llvm::getAsSignedInteger(arg, 10, w))
+      return O.error("Invalid argument '" + arg +
+                     "', only integer is supported.");
+    v = w;
+    return false;
+  }
+};
+
 } // namespace
 
 } // namespace iree_compiler
@@ -115,6 +129,19 @@
         compileToPhases.push_back(name.str());
       });
 
+  llvm::cl::opt<bool> emitMLIRBytecode(
+      "emit-mlir-bytecode",
+      llvm::cl::desc(
+          "Emit bytecode when generating compile-to or VM MLIR output."),
+      llvm::cl::init(false));
+  llvm::cl::opt<std::optional<int64_t>, /*ExternalStorage=*/false,
+                mlir::iree_compiler::BytecodeVersionParser>
+      emitMLIRBytecodeVersion(
+          "emit-mlir-bytecode-version",
+          llvm::cl::desc("Use specified bytecode version when "
+                         "generating compile-to or VM MLIR output."),
+          llvm::cl::init(std::nullopt));
+
   // Misc options.
   llvm::cl::opt<bool> splitInputFile(
       "split-input-file",
@@ -230,9 +257,19 @@
       return false;
     }
 
+    auto outputMLIR = [&](iree_compiler_invocation_t *inv,
+                          iree_compiler_output_t *output) {
+      if (emitMLIRBytecode) {
+        return ireeCompilerInvocationOutputIRBytecode(
+            inv, output, emitMLIRBytecodeVersion.value_or(-1));
+      } else {
+        return ireeCompilerInvocationOutputIR(inv, output);
+      }
+    };
+
     // Ending early and just emitting IR.
     if (compileTo != IREEVMPipelinePhase::End) {
-      if (auto error = ireeCompilerInvocationOutputIR(r.inv, s.output)) {
+      if (auto error = outputMLIR(r.inv, s.output)) {
         s.handleError(error);
         return false;
       }
@@ -243,7 +280,7 @@
     iree_compiler_error_t *outputError = nullptr;
     switch (outputFormat) {
     case OutputFormat::vm_asm:
-      outputError = ireeCompilerInvocationOutputIR(r.inv, s.output);
+      outputError = outputMLIR(r.inv, s.output);
       break;
     case OutputFormat::vm_bytecode:
       outputError = ireeCompilerInvocationOutputVMBytecode(r.inv, s.output);