Adding std-to-vm conversion.
Designed to be used as a set of conversion patterns but also exposed as a pass for easy testing. Currently only handles types supported by the VM (I32) and I1 promotion, with rewrites that insert type conversion left for future CLs.

This was harder than I expected due to being near the front of the line in exercising new features:
* DialectConversion of module ops (only supported for nested modules, not top-level modules)
* Type conversions for functions and call ops.
* DRR rewrites not supported for DialectConversion (message sent to list and Lei is going to look into it).

PiperOrigin-RevId: 281205935
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD b/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD
new file mode 100644
index 0000000..1b6d052
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD
@@ -0,0 +1,27 @@
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+cc_library(
+    name = "StandardToVM",
+    srcs = [
+        "ConvertStandardToVM.cpp",
+        "ConvertStandardToVMPass.cpp",
+    ],
+    hdrs = [
+        "ConvertStandardToVM.h",
+    ],
+    deps = [
+        "//iree/compiler/Dialect",
+        "//iree/compiler/Dialect/VM/IR",
+        "@llvm//:support",
+        "@local_config_mlir//:IR",
+        "@local_config_mlir//:Pass",
+        "@local_config_mlir//:StandardOps",
+        "@local_config_mlir//:Support",
+        "@local_config_mlir//:TransformUtils",
+        "@local_config_mlir//:Transforms",
+    ],
+    alwayslink = 1,
+)
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp
new file mode 100644
index 0000000..3ad9eab
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp
@@ -0,0 +1,376 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h"
+
+#include "iree/compiler/Dialect/VM/IR/VMOps.h"
+#include "mlir/Dialect/StandardOps/Ops.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/Function.h"
+#include "mlir/IR/Matchers.h"
+#include "mlir/IR/Module.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+namespace {
+
+class VmTypeConverter : public TypeConverter {
+ public:
+  static TypeConverter &getInstance() {
+    static VmTypeConverter instance;
+    return instance;
+  }
+
+ private:
+  Type convertType(Type t) override {
+    if (auto integerType = t.dyn_cast<IntegerType>()) {
+      if (integerType.getIntOrFloatBitWidth() == 32) {
+        return t;
+      } else if (integerType.getIntOrFloatBitWidth() == 1) {
+        // Promote i1 -> i32.
+        return IntegerType::get(32, t.getContext());
+      }
+    }
+    // Default to not supporting the type. This dialect is very limited
+    // with respect to valid types and the above should be expanded as
+    // needed.
+    return {};
+  }
+};
+
+class ModuleOpConversion : public OpConversionPattern<ModuleOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      ModuleOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    // Do not attempt to convert the top level module.
+    // This mechanism can only support rewriting non top-level modules.
+    if (!srcOp.getParentOp()) {
+      return matchFailure();
+    }
+
+    StringRef name = srcOp.getName() ? *srcOp.getName() : "module";
+    auto newModuleOp =
+        rewriter.create<IREE::VM::ModuleOp>(srcOp.getLoc(), name);
+    newModuleOp.getBodyRegion().takeBody(srcOp.getBodyRegion());
+
+    // Replace the terminator.
+    Operation *srcTerminator =
+        newModuleOp.getBodyRegion().back().getTerminator();
+    rewriter.setInsertionPointToEnd(&newModuleOp.getBodyRegion().back());
+    rewriter.replaceOpWithNewOp<IREE::VM::ModuleEndOp>(srcTerminator);
+
+    rewriter.eraseOp(srcOp);
+    return matchSuccess();
+  }
+};
+
+class FuncOpConversion : public OpConversionPattern<FuncOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      FuncOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    FunctionType srcFuncType = srcOp.getType();
+    TypeConverter &typeConverter = VmTypeConverter::getInstance();
+    TypeConverter::SignatureConversion signatureConversion(
+        srcOp.getNumArguments());
+
+    // Convert function arguments.
+    for (unsigned i = 0, e = srcFuncType.getNumInputs(); i < e; ++i) {
+      if (failed(typeConverter.convertSignatureArg(i, srcFuncType.getInput(i),
+                                                   signatureConversion))) {
+        return matchFailure();
+      }
+    }
+
+    // Convert function results.
+    SmallVector<Type, 1> convertedResultTypes;
+    if (failed(typeConverter.convertTypes(srcFuncType.getResults(),
+                                          convertedResultTypes))) {
+      return matchFailure();
+    }
+
+    // Create new function with converted argument and result types.
+    // Note that attributes are dropped. Consider preserving some if needed.
+    auto newFuncType =
+        mlir::FunctionType::get(signatureConversion.getConvertedTypes(),
+                                convertedResultTypes, srcOp.getContext());
+    auto newFuncOp = rewriter.create<IREE::VM::FuncOp>(
+        srcOp.getLoc(), srcOp.getName(), newFuncType);
+
+    // Move the body region from src -> new.
+    auto &srcRegion = srcOp.getOperation()->getRegion(0);
+    auto &newRegion = newFuncOp.getOperation()->getRegion(0);
+    newRegion.takeBody(srcRegion);
+
+    // Tell the rewriter to convert the region signature.
+    rewriter.applySignatureConversion(&newFuncOp.getBody(),
+                                      signatureConversion);
+
+    rewriter.replaceOp(srcOp, llvm::None);
+    return matchSuccess();
+  }
+};
+
+class ReturnOpConversion : public OpConversionPattern<ReturnOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      ReturnOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<IREE::VM::ReturnOp>(srcOp, operands);
+    return matchSuccess();
+  }
+};
+
+class ConstantOpConversion : public OpConversionPattern<ConstantOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      ConstantOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    auto integerAttr = srcOp.getValue().dyn_cast<IntegerAttr>();
+    // Only 32bit integer supported for now.
+    if (!integerAttr) {
+      srcOp.emitRemark() << "unsupported const type for dialect";
+      return matchFailure();
+    }
+    int numBits = integerAttr.getType().getIntOrFloatBitWidth();
+    if (numBits != 1 && numBits != 32) {
+      srcOp.emitRemark() << "unsupported bit width for dialect constant";
+      return matchFailure();
+    }
+
+    auto intValue = integerAttr.getInt();
+    if (intValue == 0) {
+      rewriter.replaceOpWithNewOp<IREE::VM::ConstI32ZeroOp>(srcOp);
+    } else {
+      rewriter.replaceOpWithNewOp<IREE::VM::ConstI32Op>(srcOp, intValue);
+    }
+    return matchSuccess();
+  }
+};
+
+class CmpIOpConversion : public OpConversionPattern<CmpIOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      CmpIOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    CmpIOpOperandAdaptor srcAdapter(operands);
+    auto returnType = rewriter.getIntegerType(32);
+    switch (srcOp.getPredicate()) {
+      case CmpIPredicate::eq:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpEQI32Op>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::ne:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpNEI32Op>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::slt:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpLTI32SOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::sle:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpLTEI32SOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::sgt:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpGTI32SOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::sge:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpGTEI32SOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::ult:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpLTI32UOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::ule:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpLTEI32UOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::ugt:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpGTI32UOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+      case CmpIPredicate::uge:
+        rewriter.replaceOpWithNewOp<IREE::VM::CmpGTEI32UOp>(
+            srcOp, returnType, srcAdapter.lhs(), srcAdapter.rhs());
+        return matchSuccess();
+    }
+  }
+};
+
+template <typename SrcOpTy, typename DstOpTy>
+class BinaryArithmeticOpConversion : public OpConversionPattern<SrcOpTy> {
+  using OpConversionPattern<SrcOpTy>::OpConversionPattern;
+  using OpConversionPattern<SrcOpTy>::matchSuccess;
+
+  PatternMatchResult matchAndRewrite(
+      SrcOpTy srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    typename SrcOpTy::OperandAdaptor srcAdapter(operands);
+
+    rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getType(),
+                                         srcAdapter.lhs(), srcAdapter.rhs());
+    return matchSuccess();
+  }
+};
+
+template <typename SrcOpTy, typename DstOpTy, unsigned kBits = 32>
+class ShiftArithmeticOpConversion : public OpConversionPattern<SrcOpTy> {
+  using OpConversionPattern<SrcOpTy>::OpConversionPattern;
+  using OpConversionPattern<SrcOpTy>::matchFailure;
+  using OpConversionPattern<SrcOpTy>::matchSuccess;
+
+  PatternMatchResult matchAndRewrite(
+      SrcOpTy srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    typename SrcOpTy::OperandAdaptor srcAdaptor(operands);
+    auto type = srcOp.getType();
+    if (!type.template isa<IntegerType>() ||
+        type.getIntOrFloatBitWidth() != kBits) {
+      return matchFailure();
+    }
+    APInt amount;
+    if (!matchPattern(srcAdaptor.rhs(), m_ConstantInt(&amount))) {
+      return matchFailure();
+    }
+    uint64_t amountRaw = amount.getZExtValue();
+    if (amountRaw > kBits) return matchFailure();
+    IntegerAttr amountAttr =
+        IntegerAttr::get(IntegerType::get(8, srcOp.getContext()), amountRaw);
+    rewriter.replaceOpWithNewOp<DstOpTy>(srcOp, srcOp.getType(),
+                                         srcAdaptor.lhs(), amountAttr);
+    return matchSuccess();
+  }
+};
+
+class SelectI32OpConversion : public OpConversionPattern<SelectOp> {
+  using OpConversionPattern::OpConversionPattern;
+  static constexpr unsigned kBits = 32;
+
+  PatternMatchResult matchAndRewrite(
+      SelectOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    SelectOpOperandAdaptor srcAdaptor(operands);
+    IntegerType requiredType = IntegerType::get(kBits, srcOp.getContext());
+    if (srcAdaptor.true_value()->getType() != requiredType)
+      return matchFailure();
+
+    rewriter.replaceOpWithNewOp<IREE::VM::SelectI32Op>(
+        srcOp, requiredType, srcAdaptor.condition(), srcAdaptor.true_value(),
+        srcAdaptor.false_value());
+    return matchSuccess();
+  }
+};
+
+class BranchOpConversion : public OpConversionPattern<BranchOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      BranchOp srcOp, ArrayRef<Value *> properOperands,
+      ArrayRef<Block *> destinations, ArrayRef<ArrayRef<Value *>> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    assert(destinations.size() == 1 && operands.size() == 1);
+    rewriter.replaceOpWithNewOp<IREE::VM::BranchOp>(srcOp, destinations[0],
+                                                    operands[0]);
+    return matchSuccess();
+  }
+};
+
+class CondBranchOpConversion : public OpConversionPattern<CondBranchOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      CondBranchOp srcOp, ArrayRef<Value *> properOperands,
+      ArrayRef<Block *> destinations, ArrayRef<ArrayRef<Value *>> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    assert(destinations.size() == 2 && operands.size() == 2);
+    CondBranchOpOperandAdaptor srcAdaptor(properOperands);
+    rewriter.replaceOpWithNewOp<IREE::VM::CondBranchOp>(
+        srcOp, srcAdaptor.condition(), destinations[0], operands[0],  // true
+        destinations[1], operands[1]);                                // false;
+    return matchSuccess();
+  }
+};
+
+class CallOpConversion : public OpConversionPattern<CallOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  PatternMatchResult matchAndRewrite(
+      CallOp srcOp, ArrayRef<Value *> operands,
+      ConversionPatternRewriter &rewriter) const override {
+    CallOpOperandAdaptor srcAdaptor(operands);
+    // Convert function result types. The conversion framework will ensure
+    // that the callee has been equivalently converted.
+    auto &typeConverter = VmTypeConverter::getInstance();
+    SmallVector<Type, 4> resultTypes;
+    for (auto resultType : srcOp.getResultTypes()) {
+      resultType = typeConverter.convertType(resultType);
+      if (!resultType) {
+        return matchFailure();
+      }
+      resultTypes.push_back(resultType);
+    }
+    rewriter.replaceOpWithNewOp<IREE::VM::CallOp>(
+        srcOp, srcOp.getCallee(), resultTypes, srcAdaptor.operands());
+
+    return matchSuccess();
+  }
+};
+
+}  // namespace
+
+void populateStandardToVMPatterns(MLIRContext *context,
+                                  OwningRewritePatternList &patterns) {
+  patterns
+      .insert<BranchOpConversion, CallOpConversion, CmpIOpConversion,
+              CondBranchOpConversion, ConstantOpConversion, ModuleOpConversion,
+              FuncOpConversion, ReturnOpConversion, SelectI32OpConversion>(
+          context);
+
+  // Binary arithmetic ops
+  patterns.insert<BinaryArithmeticOpConversion<AddIOp, IREE::VM::AddI32Op>,
+                  BinaryArithmeticOpConversion<DivISOp, IREE::VM::DivI32SOp>,
+                  BinaryArithmeticOpConversion<DivIUOp, IREE::VM::DivI32UOp>,
+                  BinaryArithmeticOpConversion<MulIOp, IREE::VM::MulI32Op>,
+                  BinaryArithmeticOpConversion<RemISOp, IREE::VM::RemI32SOp>,
+                  BinaryArithmeticOpConversion<RemIUOp, IREE::VM::RemI32UOp>,
+                  BinaryArithmeticOpConversion<SubIOp, IREE::VM::SubI32Op>,
+                  BinaryArithmeticOpConversion<AndOp, IREE::VM::AndI32Op>,
+                  BinaryArithmeticOpConversion<OrOp, IREE::VM::OrI32Op>,
+                  BinaryArithmeticOpConversion<XOrOp, IREE::VM::XorI32Op>>(
+      context);
+
+  // Shift ops
+  // TODO(laurenzo): The standard dialect is missing shr ops. Add once in place.
+  patterns.insert<ShiftArithmeticOpConversion<ShlISOp, IREE::VM::ShlI32Op>>(
+      context);
+}
+
+TypeConverter *getStandardToVMTypeConverter() {
+  return &VmTypeConverter::getInstance();
+}
+
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h
new file mode 100644
index 0000000..7c3e787
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h
@@ -0,0 +1,35 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef IREE_COMPILER_DIALECT_VM_CONVERSION_STANDARDTOVM_CONVERTSTANDARDTOVM_H_
+#define IREE_COMPILER_DIALECT_VM_CONVERSION_STANDARDTOVM_CONVERTSTANDARDTOVM_H_
+
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+// Appends standard dialect to vm dialect patterns to the given pattern list.
+void populateStandardToVMPatterns(MLIRContext *context,
+                                  OwningRewritePatternList &patterns);
+
+// Gets the TypeConverter that must be used for legalizing the standard to
+// VM dialect.
+TypeConverter *getStandardToVMTypeConverter();
+
+}  // namespace iree_compiler
+}  // namespace mlir
+
+#endif  // IREE_COMPILER_DIALECT_VM_CONVERSION_STANDARDTOVM_CONVERTSTANDARDTOVM_H_
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp
new file mode 100644
index 0000000..52f63b6
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp
@@ -0,0 +1,54 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h"
+#include "iree/compiler/Dialect/VM/IR/VMDialect.h"
+#include "mlir/Dialect/StandardOps/Ops.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+namespace mlir {
+namespace iree_compiler {
+
+namespace {
+
+// A pass converting MLIR Standard operations into the IREE VM dialect.
+// Used only for testing as in the common case we only rely on rewrite patterns.
+class ConvertStandardToVMPass : public ModulePass<ConvertStandardToVMPass> {
+  void runOnModule() override {
+    OwningRewritePatternList patterns;
+    auto module = getModule();
+
+    populateStandardToVMPatterns(&getContext(), patterns);
+    ConversionTarget target(getContext());
+    target.addLegalDialect<IREE::VM::VMDialect>();
+    target.addIllegalDialect<StandardOpsDialect>();
+
+    // NOTE: we allow other dialects besides just VM during this pass as we are
+    // only trying to eliminate the std ops. When used as part of a larger set
+    // of rewrites a full conversion should be used instead.
+    if (failed(applyPartialConversion(module, target, patterns,
+                                      getStandardToVMTypeConverter()))) {
+      return signalPassFailure();
+    }
+  }
+};
+
+}  // namespace
+
+static PassRegistration<ConvertStandardToVMPass> pass(
+    "iree-convert-std-to-vm", "Convert Standard Ops to the IREE VM dialect");
+
+}  // namespace iree_compiler
+}  // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/BUILD b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/BUILD
new file mode 100644
index 0000000..dc90cdc
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/BUILD
@@ -0,0 +1,14 @@
+load("//iree:build_defs.bzl", "iree_glob_lit_tests", "iree_setup_lit_package")
+
+package(
+    default_visibility = ["//visibility:public"],
+    licenses = ["notice"],  # Apache 2.0
+)
+
+iree_setup_lit_package(
+    data = [
+        "//iree/tools:iree-opt",
+    ],
+)
+
+iree_glob_lit_tests()
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/arithmetic_ops.mlir b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/arithmetic_ops.mlir
new file mode 100644
index 0000000..d9f3984
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/arithmetic_ops.mlir
@@ -0,0 +1,202 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// RUN: iree-opt -split-input-file -pass-pipeline='iree-convert-std-to-vm' %s | FileCheck %s --dump-input=fail
+
+// -----
+// CHECK-LABEL: @t001_addi
+module @t001_addi {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.add.i32 [[ARG0]], [[ARG1]]
+    %0 = addi %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t002_divis
+module @t002_divis {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.div.i32.s [[ARG0]], [[ARG1]]
+    %0 = divis %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t002_diviu
+module @t002_diviu {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.div.i32.u [[ARG0]], [[ARG1]]
+    %0 = diviu %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t003_muli
+module @t003_muli {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.mul.i32 [[ARG0]], [[ARG1]]
+    %0 = muli %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t004_remis
+module @t004_remis {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.rem.i32.s [[ARG0]], [[ARG1]]
+    %0 = remis %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t005_remiu
+module @t005_remiu {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.rem.i32.u [[ARG0]], [[ARG1]]
+    %0 = remiu %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t006_subi
+module @t006_subi {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.sub.i32 [[ARG0]], [[ARG1]]
+    %0 = subi %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t007_and
+module @t007_and {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.and.i32 [[ARG0]], [[ARG1]]
+    %0 = and %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t008_or
+module @t008_or {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.or.i32 [[ARG0]], [[ARG1]]
+    %0 = or %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t009_xor
+module @t009_xor {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1: i32) -> (i32) {
+    // CHECK: vm.xor.i32 [[ARG0]], [[ARG1]]
+    %0 = xor %arg0, %arg1 : i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t010_shift
+module @t010_shift {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32) -> (i32) {
+    %cst = constant 3 : i32
+    // CHECK: vm.shl.i32 [[ARG0]], 3 : i32
+    %1 = shlis %arg0, %cst : i32
+    return %1 : i32
+  }
+}
+
+}
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/assignment_ops.mlir b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/assignment_ops.mlir
new file mode 100644
index 0000000..7f5a412
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/assignment_ops.mlir
@@ -0,0 +1,36 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// RUN: iree-opt -split-input-file -pass-pipeline='iree-convert-std-to-vm' %s | FileCheck %s --dump-input=fail
+
+// -----
+// CHECK-LABEL: @t001_cmp_select
+module @t001_cmp_select {
+
+module @my_module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0 : i32, %arg1 : i32) -> (i32) {
+    // Note that in std, cmp returns an i1 and this relies on the dialect
+    // conversion framework promoting that to i32.
+    // CHECK: [[CMP:%[a-zA-Z0-9]+]] = vm.cmp.eq.i32
+    %1 = cmpi "eq", %arg0, %arg1 : i32
+    // CHECK: vm.select.i32 [[CMP]], [[ARG0]], [[ARG1]] : i32
+    %2 = select %1, %arg0, %arg1 : i32
+    return %2 : i32
+  }
+}
+
+}
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/comparison_ops.mlir b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/comparison_ops.mlir
new file mode 100644
index 0000000..482e42c
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/comparison_ops.mlir
@@ -0,0 +1,185 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// RUN: iree-opt -split-input-file -pass-pipeline='iree-convert-std-to-vm' %s | FileCheck %s --dump-input=fail
+
+// -----
+// CHECK-LABEL: @t001_cmp_eq_i32
+module @t001_cmp_eq_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.eq.i32 [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "eq", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t002_cmp_ne_i32
+module @t002_cmp_ne_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.ne.i32 [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "ne", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t003_cmp_slt_i32
+module @t003_cmp_slt_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.lt.i32.s [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "slt", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t004_cmp_sle_i32
+module @t004_cmp_sle_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.lte.i32.s [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "sle", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t005_cmp_sgt_i32
+module @t005_cmp_sgt_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.gt.i32.s [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "sgt", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t006_cmp_sge_i32
+module @t006_cmp_sge_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.gte.i32.s [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "sge", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t007_cmp_ult_i32
+module @t007_cmp_ult_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.lt.i32.u [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "ult", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t008_cmp_ule_i32
+module @t008_cmp_ule_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.lte.i32.u [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "ule", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t009_cmp_ugt_i32
+module @t009_cmp_ugt_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.gt.i32.u [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "ugt", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t010_cmp_uge_i32
+module @t010_cmp_uge_i32 {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0: i32, %arg1 : i32) -> (i1) {
+    // CHECK: vm.cmp.gte.i32.u [[ARG0]], [[ARG1]] : i32
+    %1 = cmpi "uge", %arg0, %arg1 : i32
+    return %1 : i1
+  }
+}
+
+}
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/const_ops.mlir b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/const_ops.mlir
new file mode 100644
index 0000000..c39357b
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/const_ops.mlir
@@ -0,0 +1,43 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// RUN: iree-opt -split-input-file -pass-pipeline='iree-convert-std-to-vm' %s | FileCheck %s --dump-input=fail
+
+// -----
+// CHECK-LABEL: @t001_const.i32.nonzero
+module @t001_const.i32.nonzero {
+
+module {
+  func @non_zero() -> (i32) {
+    // CHECK: vm.const.i32 1 : i32
+    %1 = constant 1 : i32
+    return %1 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t001_const.i32.zero
+module @t001_const.i32.zero {
+
+module {
+  func @zero() -> (i32) {
+    // CHECK: vm.const.i32.zero : i32
+    %1 = constant 0 : i32
+    return %1 : i32
+  }
+}
+
+}
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/control_flow_ops.mlir b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/control_flow_ops.mlir
new file mode 100644
index 0000000..7a97050
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/control_flow_ops.mlir
@@ -0,0 +1,122 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// RUN: iree-opt -split-input-file -pass-pipeline='iree-convert-std-to-vm' %s | FileCheck %s --dump-input=fail
+
+// -----
+// CHECK-LABEL: @t001_br
+module @t001_br {
+
+module {
+  func @my_fn(%arg0 : i32) -> (i32) {
+    // CHECK: vm.br ^bb1
+    br ^bb1
+  ^bb1:
+    return %arg0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t002_cond_br
+module @t002_cond_br {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0 : i1, %arg1 : i32, %arg2 : i32) -> (i32) {
+    // CHECK: vm.cond_br [[ARG0]], ^bb1, ^bb2
+    cond_br %arg0, ^bb1, ^bb2
+  ^bb1:
+    return %arg1 : i32
+  ^bb2:
+    return %arg2 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t003_br_args
+module @t003_br_args {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0 : i32, %arg1 : i32) -> (i32) {
+    // CHECK: vm.br ^bb1([[ARG0]], [[ARG1]] : i32, i32)
+    br ^bb1(%arg0, %arg1 : i32, i32)
+  ^bb1(%0 : i32, %1 : i32):
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t004_cond_br_args
+module @t004_cond_br_args {
+
+module {
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG1:%[a-zA-Z0-9]+]]
+  // CHECK-SAME: [[ARG2:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0 : i1, %arg1 : i32, %arg2 : i32) -> (i32) {
+    // CHECK: vm.cond_br [[ARG0]], ^bb1([[ARG1]] : i32), ^bb2([[ARG2]] : i32)
+    cond_br %arg0, ^bb1(%arg1 : i32), ^bb2(%arg2 : i32)
+  ^bb1(%0 : i32):
+    return %0 : i32
+  ^bb2(%1 : i32):
+    return %1 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t005_call
+module @t005_call {
+
+module {
+  func @import_fn(%arg0 : i32) -> i32
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0 : i32) -> (i32) {
+    // CHECK: vm.call @import_fn([[ARG0]]) : (i32) -> i32
+    %0 = call @import_fn(%arg0) : (i32) -> i32
+    return %0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t005_call_int_promotion
+module @t005_call_int_promotion {
+
+module {
+  func @import_fn(%arg0 : i1) -> i1
+  // CHECK: func @my_fn
+  // CHECK-SAME: [[ARG0:%[a-zA-Z0-9]+]]
+  func @my_fn(%arg0 : i1) -> (i1) {
+    // CHECK: vm.call @import_fn([[ARG0]]) : (i32) -> i32
+    %0 = call @import_fn(%arg0) : (i1) -> i1
+    return %0 : i1
+  }
+}
+
+}
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/structural_ops.mlir b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/structural_ops.mlir
new file mode 100644
index 0000000..bcf2ef7
--- /dev/null
+++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/test/structural_ops.mlir
@@ -0,0 +1,56 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// RUN: iree-opt -split-input-file -pass-pipeline='iree-convert-std-to-vm' %s | FileCheck %s --dump-input=fail
+
+// -----
+// Checks literal specifics of structural transforms (more verbose checks
+// than usual since the conversion code is manual).
+// CHECK-LABEL: @t001_module_all_options
+module @t001_module_all_options {
+
+// CHECK: module @my_module {
+module @my_module {
+  // CHECK: vm.func @my_fn([[ARG0:%[a-zA-Z0-9]+]]: i32) -> i32
+  func @my_fn(%arg0: i32) -> (i32) {
+    // CHECK: vm.return [[ARG0]] : i32
+    return %arg0 : i32
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t002_no_args_results
+module @t002_no_args_results {
+
+module @my_module {
+  // CHECK: vm.func @my_fn() {
+  func @my_fn() -> () {
+    // CHECK: vm.return
+    return
+  }
+}
+
+}
+
+// -----
+// CHECK-LABEL: @t003_unnamed_module
+module @t003_unnamed_module {
+
+// CHECK: module @module {
+module {
+}
+
+}
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index b0d1bdf..f9ae673 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -33,6 +33,7 @@
         "//integrations/tensorflow/compiler:tensorflow",
         "//iree/compiler/Dialect",
         "//iree/compiler/Dialect/VM/Analysis",
+        "//iree/compiler/Dialect/VM/Conversion/StandardToVM",
         "//iree/compiler/Dialect/VM/IR",
         "//iree/compiler/Dialect/VM/Transforms",
         "//iree/compiler/Transforms",