Adding i32/i64/f32 min/max ops.
These cover a large number of ops in common loops and will be easy to
lower to native machine instructions.
diff --git a/compiler/src/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp b/compiler/src/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp
index a6b46b3..0383473 100644
--- a/compiler/src/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp
+++ b/compiler/src/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp
@@ -1107,6 +1107,14 @@
                                            IREE::VM::RemI64SOp>,
               BinaryArithmeticOpConversion<arith::RemUIOp, IREE::VM::RemI32UOp,
                                            IREE::VM::RemI64UOp>,
+              BinaryArithmeticOpConversion<arith::MinSIOp, IREE::VM::MinI32SOp,
+                                           IREE::VM::MinI64SOp>,
+              BinaryArithmeticOpConversion<arith::MinUIOp, IREE::VM::MinI32UOp,
+                                           IREE::VM::MinI64UOp>,
+              BinaryArithmeticOpConversion<arith::MaxSIOp, IREE::VM::MaxI32SOp,
+                                           IREE::VM::MaxI64SOp>,
+              BinaryArithmeticOpConversion<arith::MaxUIOp, IREE::VM::MaxI32UOp,
+                                           IREE::VM::MaxI64UOp>,
               BinaryArithmeticOpConversion<arith::SubIOp, IREE::VM::SubI32Op,
                                            IREE::VM::SubI64Op>,
               BinaryArithmeticOpConversion<arith::AndIOp, IREE::VM::AndI32Op,
@@ -1136,7 +1144,11 @@
               BinaryArithmeticOpConversion<arith::RemFOp, IREE::VM::RemF32Op,
                                            IREE::VM::RemF64Op>,
               BinaryArithmeticOpConversion<arith::SubFOp, IREE::VM::SubF32Op,
-                                           IREE::VM::SubF64Op>>(typeConverter,
+                                           IREE::VM::SubF64Op>,
+              BinaryArithmeticOpConversion<arith::MinFOp, IREE::VM::MinF32Op,
+                                           IREE::VM::MinF64Op>,
+              BinaryArithmeticOpConversion<arith::MaxFOp, IREE::VM::MaxF32Op,
+                                           IREE::VM::MaxF64Op>>(typeConverter,
                                                                 context);
 
   // Floating-point conversion ops.
diff --git a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/ConvertVMToEmitC.cpp b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/ConvertVMToEmitC.cpp
index d387070..2030dd8 100644
--- a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/ConvertVMToEmitC.cpp
+++ b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/ConvertVMToEmitC.cpp
@@ -4312,6 +4312,14 @@
                                                         "vm_fma_i32");
   patterns.add<GenericOpConversion<IREE::VM::AbsI32Op>>(typeConverter, context,
                                                         "vm_abs_i32");
+  patterns.add<GenericOpConversion<IREE::VM::MinI32SOp>>(typeConverter, context,
+                                                         "vm_min_i32s");
+  patterns.add<GenericOpConversion<IREE::VM::MinI32UOp>>(typeConverter, context,
+                                                         "vm_min_i32u");
+  patterns.add<GenericOpConversion<IREE::VM::MaxI32SOp>>(typeConverter, context,
+                                                         "vm_max_i32s");
+  patterns.add<GenericOpConversion<IREE::VM::MaxI32UOp>>(typeConverter, context,
+                                                         "vm_max_i32u");
   patterns.add<GenericOpConversion<IREE::VM::NotI32Op>>(typeConverter, context,
                                                         "vm_not_i32");
   patterns.add<GenericOpConversion<IREE::VM::AndI32Op>>(typeConverter, context,
@@ -4413,6 +4421,10 @@
       typeConverter, context, "vm_floor_f32");
   patterns.add<GenericOpConversion<IREE::VM::RoundF32Op>>(
       typeConverter, context, "vm_round_f32");
+  patterns.add<GenericOpConversion<IREE::VM::MinF32Op>>(typeConverter, context,
+                                                        "vm_min_f32");
+  patterns.add<GenericOpConversion<IREE::VM::MaxF32Op>>(typeConverter, context,
+                                                        "vm_max_f32");
 
   patterns.add<GenericOpConversion<IREE::VM::AtanF32Op>>(typeConverter, context,
                                                          "vm_atan_f32");
@@ -4534,6 +4546,14 @@
                                                         "vm_fma_i64");
   patterns.add<GenericOpConversion<IREE::VM::AbsI64Op>>(typeConverter, context,
                                                         "vm_abs_i64");
+  patterns.add<GenericOpConversion<IREE::VM::MinI64SOp>>(typeConverter, context,
+                                                         "vm_min_i64s");
+  patterns.add<GenericOpConversion<IREE::VM::MinI64UOp>>(typeConverter, context,
+                                                         "vm_min_i64u");
+  patterns.add<GenericOpConversion<IREE::VM::MaxI64SOp>>(typeConverter, context,
+                                                         "vm_max_i64s");
+  patterns.add<GenericOpConversion<IREE::VM::MaxI64UOp>>(typeConverter, context,
+                                                         "vm_max_i64u");
   patterns.add<GenericOpConversion<IREE::VM::NotI64Op>>(typeConverter, context,
                                                         "vm_not_i64");
   patterns.add<GenericOpConversion<IREE::VM::AndI64Op>>(typeConverter, context,
diff --git a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops.mlir b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops.mlir
index 6ef3fcd..c1ff692 100644
--- a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops.mlir
+++ b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops.mlir
@@ -99,6 +99,17 @@
 
 // -----
 
+// CHECK-LABEL: @my_module_min_i32_s
+vm.module @my_module {
+  vm.func @min_i32_s(%arg0: i32, %arg1: i32) {
+    // CHECK: %0 = emitc.call "vm_min_i32s"(%arg3, %arg4) : (i32, i32) -> i32
+    %0 = vm.min.i32.s %arg0, %arg1 : i32
+    vm.return %0 : i32
+  }
+}
+
+// -----
+
 // CHECK-LABEL: @my_module_not_i32
 vm.module @my_module {
   vm.func @not_i32(%arg0 : i32) -> i32 {
diff --git a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_f32.mlir b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_f32.mlir
index 93ad88d..d54b9b9 100644
--- a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_f32.mlir
+++ b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_f32.mlir
@@ -110,6 +110,28 @@
 
 // -----
 
+// CHECK-LABEL: @my_module_min_f32
+vm.module @my_module {
+  vm.func @min_f32(%arg0 : f32, %arg1 : f32) -> f32 {
+    // CHECK-NEXT: %0 = emitc.call "vm_min_f32"(%arg3, %arg4) : (f32, f32) -> f32
+    %0 = vm.min.f32 %arg0, %arg1 : f32
+    vm.return %0 : f32
+  }
+}
+
+// -----
+
+// CHECK-LABEL: @my_module_max_f32
+vm.module @my_module {
+  vm.func @max_f32(%arg0 : f32, %arg1 : f32) -> f32 {
+    // CHECK-NEXT: %0 = emitc.call "vm_max_f32"(%arg3, %arg4) : (f32, f32) -> f32
+    %0 = vm.max.f32 %arg0, %arg1 : f32
+    vm.return %0 : f32
+  }
+}
+
+// -----
+
 // CHECK-LABEL: @my_module_atan_f32
 vm.module @my_module {
   vm.func @atan_f32(%arg0 : f32) -> f32 {
diff --git a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_i64.mlir b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_i64.mlir
index c76c84c..dd1341d 100644
--- a/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_i64.mlir
+++ b/compiler/src/iree/compiler/Dialect/VM/Conversion/VMToEmitC/test/arithmetic_ops_i64.mlir
@@ -99,6 +99,17 @@
 
 // -----
 
+// CHECK-LABEL: @my_module_min_i64_s
+vm.module @my_module {
+  vm.func @min_i64_s(%arg0: i64, %arg1: i64) {
+    // CHECK: %0 = emitc.call "vm_min_i64s"(%arg3, %arg4) : (i64, i64) -> i64
+    %0 = vm.min.i64.s %arg0, %arg1 : i64
+    vm.return %0 : i64
+  }
+}
+
+// -----
+
 // CHECK-LABEL: @my_module_not_i64
 vm.module @my_module {
   vm.func @not_i64(%arg0 : i64) -> i64 {
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpFolders.cpp b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpFolders.cpp
index 20b2551..6fae72b 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpFolders.cpp
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpFolders.cpp
@@ -955,6 +955,70 @@
                                        [](const APInt &a) { return a.abs(); });
 }
 
+OpFoldResult MinI32SOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::smin(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MinI64SOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::smin(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MinI32UOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::umin(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MinI64UOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::umin(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MaxI32SOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::smax(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MaxI64SOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::smax(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MaxI32UOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::umax(lhs, rhs);
+                                        });
+}
+
+OpFoldResult MaxI64UOp::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<IntegerAttr>(operands.getLhs(), operands.getRhs(),
+                                        [](const APInt &lhs, const APInt &rhs) {
+                                          return llvm::APIntOps::umax(lhs, rhs);
+                                        });
+}
+
 //===----------------------------------------------------------------------===//
 // Floating-point arithmetic
 //===----------------------------------------------------------------------===//
@@ -1165,6 +1229,32 @@
   });
 }
 
+OpFoldResult MinF32Op::fold(FoldAdaptor operands) {
+  return constFoldBinaryOp<FloatAttr>(
+      operands.getLhs(), operands.getRhs(),
+      [](const APFloat &a, const APFloat &b) { return llvm::minnum(a, b); });
+}
+
+OpFoldResult MinF64Op::fold(FoldAdaptor operands) {
+  return constFoldBinaryOp<FloatAttr>(
+      operands.getLhs(), operands.getRhs(),
+      [](const APFloat &a, const APFloat &b) { return llvm::minnum(a, b); });
+}
+
+OpFoldResult MaxF32Op::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<FloatAttr>(
+      operands.getLhs(), operands.getRhs(),
+      [](const APFloat &a, const APFloat &b) { return llvm::maxnum(a, b); });
+}
+
+OpFoldResult MaxF64Op::fold(FoldAdaptor operands) {
+  if (getLhs() == getRhs()) return getLhs();
+  return constFoldBinaryOp<FloatAttr>(
+      operands.getLhs(), operands.getRhs(),
+      [](const APFloat &a, const APFloat &b) { return llvm::maxnum(a, b); });
+}
+
 //===----------------------------------------------------------------------===//
 // Floating-point math
 //===----------------------------------------------------------------------===//
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesCore.td b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesCore.td
index b271b5c..901983c 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesCore.td
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesCore.td
@@ -47,7 +47,7 @@
   string opcodeEnumTag = enumTag;
 }
 
-// Next available opcode: 0x7A
+// Next available opcode: 0x82
 
 // Globals:
 def VM_OPC_GlobalLoadI32         : VM_OPC<0x00, "GlobalLoadI32">;
@@ -107,6 +107,10 @@
 def VM_OPC_RemI32U               : VM_OPC<0x28, "RemI32U">;
 def VM_OPC_FMAI32                : VM_OPC<0x29, "FMAI32">;
 def VM_OPC_AbsI32                : VM_OPC<0x77, "AbsI32">;
+def VM_OPC_MinI32S               : VM_OPC<0x7A, "MinI32S">;
+def VM_OPC_MinI32U               : VM_OPC<0x7B, "MinI32U">;
+def VM_OPC_MaxI32S               : VM_OPC<0x7C, "MaxI32S">;
+def VM_OPC_MaxI32U               : VM_OPC<0x7D, "MaxI32U">;
 
 // 64-bit integer arithmetic:
 def VM_OPC_AddI64                : VM_OPC<0x2A, "AddI64">;
@@ -118,6 +122,10 @@
 def VM_OPC_RemI64U               : VM_OPC<0x30, "RemI64U">;
 def VM_OPC_FMAI64                : VM_OPC<0x31, "FMAI64">;
 def VM_OPC_AbsI64                : VM_OPC<0x78, "AbsI64">;
+def VM_OPC_MinI64S               : VM_OPC<0x7E, "MinI64S">;
+def VM_OPC_MinI64U               : VM_OPC<0x7F, "MinI64U">;
+def VM_OPC_MaxI64S               : VM_OPC<0x80, "MaxI64S">;
+def VM_OPC_MaxI64U               : VM_OPC<0x81, "MaxI64U">;
 
 // 32-bit integer bit manipulation:
 def VM_OPC_NotI32                : VM_OPC<0x32, "NotI32">;
@@ -272,6 +280,10 @@
     VM_OPC_RemI32U,
     VM_OPC_FMAI32,
     VM_OPC_AbsI32,
+    VM_OPC_MinI32S,
+    VM_OPC_MinI32U,
+    VM_OPC_MaxI32S,
+    VM_OPC_MaxI32U,
 
     VM_OPC_AddI64,
     VM_OPC_SubI64,
@@ -282,6 +294,10 @@
     VM_OPC_RemI64U,
     VM_OPC_FMAI64,
     VM_OPC_AbsI64,
+    VM_OPC_MinI64S,
+    VM_OPC_MinI64U,
+    VM_OPC_MaxI64S,
+    VM_OPC_MaxI64U,
 
     VM_OPC_NotI32,
     VM_OPC_AndI32,
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF32.td b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF32.td
index 1ef5d4e..11ffe5c 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF32.td
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF32.td
@@ -40,6 +40,8 @@
 def VM_OPC_CeilF32               : VM_OPC<0x12, "CeilF32">;
 def VM_OPC_FloorF32              : VM_OPC<0x13, "FloorF32">;
 def VM_OPC_RoundF32              : VM_OPC<0x36, "RoundF32">;
+def VM_OPC_MinF32                : VM_OPC<0x37, "MinF32">;
+def VM_OPC_MaxF32                : VM_OPC<0x38, "MaxF32">;
 
 def VM_OPC_CastSI32F32           : VM_OPC<0x14, "CastSI32F32">;
 def VM_OPC_CastUI32F32           : VM_OPC<0x15, "CastUI32F32">;
@@ -111,6 +113,8 @@
     VM_OPC_CeilF32,
     VM_OPC_FloorF32,
     VM_OPC_RoundF32,
+    VM_OPC_MinF32,
+    VM_OPC_MaxF32,
 
     VM_OPC_CastSI32F32,
     VM_OPC_CastUI32F32,
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF64.td b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF64.td
index 133c3ce..626ca57 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF64.td
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/VMOpcodesF64.td
@@ -42,6 +42,8 @@
 def VM_OPC_RoundF64              : VM_OPC<0x3C, "RoundF64">;
 def VM_OPC_TruncF64F32           : VM_OPC<0x14, "TruncF64F32">;
 def VM_OPC_ExtF32F64             : VM_OPC<0x15, "ExtF32F64">;
+def VM_OPC_MinF64                : VM_OPC<0x3D, "MinF64">;
+def VM_OPC_MaxF64                : VM_OPC<0x3E, "MaxF64">;
 
 def VM_OPC_CastSI32F64           : VM_OPC<0x16, "CastSI32F64">;
 def VM_OPC_CastUI32F64           : VM_OPC<0x17, "CastUI32F64">;
@@ -118,6 +120,8 @@
     VM_OPC_CeilF64,
     VM_OPC_FloorF64,
     VM_OPC_RoundF64,
+    VM_OPC_MinF64,
+    VM_OPC_MaxF64,
 
     VM_OPC_TruncF64F32,
     VM_OPC_ExtF32F64,
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/VMOps.td b/compiler/src/iree/compiler/Dialect/VM/IR/VMOps.td
index 5f916c0..f008f56 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/VMOps.td
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/VMOps.td
@@ -2211,6 +2211,54 @@
   let hasFolder = 1;
 }
 
+def VM_MinI32SOp :
+    VM_BinaryArithmeticOp<I32, "min.i32.s", VM_OPC_MinI32S, [Commutative]> {
+  let summary = [{signed integer minimum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MinI32UOp :
+    VM_BinaryArithmeticOp<I32, "min.i32.u", VM_OPC_MinI32U, [Commutative]> {
+  let summary = [{unsigned integer minimum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MinI64SOp :
+    VM_BinaryArithmeticOp<I64, "min.i64.s", VM_OPC_MinI64S, [Commutative]> {
+  let summary = [{signed integer minimum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MinI64UOp :
+    VM_BinaryArithmeticOp<I64, "min.i64.u", VM_OPC_MinI64U, [Commutative]> {
+  let summary = [{unsigned integer minimum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MaxI32SOp :
+    VM_BinaryArithmeticOp<I32, "max.i32.s", VM_OPC_MaxI32S, [Commutative]> {
+  let summary = [{signed integer maximum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MaxI32UOp :
+    VM_BinaryArithmeticOp<I32, "max.i32.u", VM_OPC_MaxI32U, [Commutative]> {
+  let summary = [{unsigned integer maximum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MaxI64SOp :
+    VM_BinaryArithmeticOp<I64, "max.i64.s", VM_OPC_MaxI64S, [Commutative]> {
+  let summary = [{signed integer maximum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MaxI64UOp :
+    VM_BinaryArithmeticOp<I64, "max.i64.u", VM_OPC_MaxI64U, [Commutative]> {
+  let summary = [{unsigned integer maximum operation}];
+  let hasFolder = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Floating-point arithmetic
 //===----------------------------------------------------------------------===//
@@ -2371,6 +2419,34 @@
   let summary = [{rounds the value to the nearest integer away from zero}];
 }
 
+def VM_MinF32Op :
+    VM_TotalBinaryArithmeticOp<F32, "min.f32", VM_OPC_MinF32,
+                               [VM_ExtF32, Commutative]> {
+  let summary = [{floating point minimum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MinF64Op :
+    VM_TotalBinaryArithmeticOp<F64, "min.f64", VM_OPC_MinF64,
+                               [VM_ExtF64, Commutative]> {
+  let summary = [{floating point minimum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MaxF32Op :
+    VM_TotalBinaryArithmeticOp<F32, "max.f32", VM_OPC_MaxF32,
+                               [VM_ExtF32, Commutative]> {
+  let summary = [{floating point maximum operation}];
+  let hasFolder = 1;
+}
+
+def VM_MaxF64Op :
+    VM_TotalBinaryArithmeticOp<F64, "max.f64", VM_OPC_MaxF64,
+                               [VM_ExtF32, Commutative]> {
+  let summary = [{floating point maximum operation}];
+  let hasFolder = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Floating-point math
 //===----------------------------------------------------------------------===//
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_folding.mlir b/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_folding.mlir
index 35080c1..d83f6a6 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_folding.mlir
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_folding.mlir
@@ -284,6 +284,46 @@
 
 // -----
 
+// CHECK-LABEL: @min_i32_folds
+vm.module @min_i32_folds {
+  // CHECK-LABEL: @min_i32_cst_y
+  vm.func @min_i32_cst_y(%arg0: i32) -> i32 {
+    %c123 = vm.const.i32 123
+    // CHECK: vm.min.i32.s %arg0, %c123 : i32
+    %0 = vm.min.i32.s %c123, %arg0 : i32
+    vm.return %0 : i32
+  }
+
+  // CHECK-LABEL: @min_i32_x_x
+  vm.func @min_i32_x_x(%arg0: i32) -> i32 {
+    // CHECK: vm.return %arg0 : i32
+    %0 = vm.min.i32.s %arg0, %arg0 : i32
+    vm.return %0 : i32
+  }
+
+  // CHECK-LABEL: @min_i32_s_const
+  vm.func @min_i32_s_const() -> i32 {
+    // CHECK: %[[CST:.+]] = vm.const.i32 -5
+    // CHECK-NEXT: vm.return %[[CST]] : i32
+    %cn5 = vm.const.i32 -5
+    %c4 = vm.const.i32 4
+    %0 = vm.min.i32.s %cn5, %c4 : i32
+    vm.return %0 : i32
+  }
+
+  // CHECK-LABEL: @min_i32_u_const
+  vm.func @min_i32_u_const() -> i32 {
+    // CHECK: %[[CST:.+]] = vm.const.i32 2147483647
+    // CHECK-NEXT: vm.return %[[CST]] : i32
+    %c7f = vm.const.i32 0x7FFFFFFF
+    %c80 = vm.const.i32 0x80000000
+    %0 = vm.min.i32.u %c7f, %c80 : i32
+    vm.return %0 : i32
+  }
+}
+
+// -----
+
 // CHECK-LABEL: @not_i32_folds
 vm.module @not_i32_folds {
   // CHECK-LABEL: @not_i32_const
diff --git a/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_ops.mlir b/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_ops.mlir
index 2787cf1..a2c8a2e 100644
--- a/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_ops.mlir
+++ b/compiler/src/iree/compiler/Dialect/VM/IR/test/arithmetic_ops.mlir
@@ -151,3 +151,25 @@
     vm.return %0 : i32
   }
 }
+
+// -----
+
+// CHECK-LABEL: @min_i32_s
+vm.module @my_module {
+  vm.func @min_i32_s(%arg0 : i32, %arg1 : i32) -> i32 {
+    // CHECK: %0 = vm.min.i32.s %arg0, %arg1 : i32
+    %0 = vm.min.i32.s %arg0, %arg1 : i32
+    vm.return %0 : i32
+  }
+}
+
+// -----
+
+// CHECK-LABEL: @max_i32_s
+vm.module @my_module {
+  vm.func @max_i32_s(%arg0 : i32, %arg1 : i32) -> i32 {
+    // CHECK: %0 = vm.max.i32.s %arg0, %arg1 : i32
+    %0 = vm.max.i32.s %arg0, %arg1 : i32
+    vm.return %0 : i32
+  }
+}
diff --git a/compiler/src/iree/compiler/Dialect/VM/Transforms/Conversion.cpp b/compiler/src/iree/compiler/Dialect/VM/Transforms/Conversion.cpp
index c54785a..f34866f 100644
--- a/compiler/src/iree/compiler/Dialect/VM/Transforms/Conversion.cpp
+++ b/compiler/src/iree/compiler/Dialect/VM/Transforms/Conversion.cpp
@@ -150,12 +150,7 @@
                                    patterns);
     populateUtilToVMPatterns(context, conversionTarget, typeConverter,
                              patterns);
-    arith::populateArithExpandOpsPatterns(patterns);
-    patterns.add<MaxMinIOpConverter<arith::MaxSIOp, arith::CmpIPredicate::sgt>,
-                 MaxMinIOpConverter<arith::MaxUIOp, arith::CmpIPredicate::ugt>,
-                 MaxMinIOpConverter<arith::MinSIOp, arith::CmpIPredicate::slt>,
-                 MaxMinIOpConverter<arith::MinUIOp, arith::CmpIPredicate::ult>>(
-        context);
+    arith::populateCeilFloorDivExpandOpsPatterns(patterns);
     populateStandardToVMPatterns(context, typeConverter, patterns);
     populateMathToVMPatterns(context, typeConverter, patterns);
     populateAffineToStdConversionPatterns(patterns);
diff --git a/runtime/src/iree/vm/bytecode/disassembler.c b/runtime/src/iree/vm/bytecode/disassembler.c
index e0fbab0..1c7bce8 100644
--- a/runtime/src/iree/vm/bytecode/disassembler.c
+++ b/runtime/src/iree/vm/bytecode/disassembler.c
@@ -1320,6 +1320,10 @@
     DISASM_OP_CORE_BINARY_I32(RemI32U, "vm.rem.i32.u");
     DISASM_OP_CORE_TERNARY_I32(FMAI32, "vm.fma.i32");
     DISASM_OP_CORE_UNARY_I32(AbsI32, "vm.abs.i32");
+    DISASM_OP_CORE_BINARY_I32(MinI32S, "vm.min.i32.s");
+    DISASM_OP_CORE_BINARY_I32(MinI32U, "vm.min.i32.u");
+    DISASM_OP_CORE_BINARY_I32(MaxI32S, "vm.max.i32.s");
+    DISASM_OP_CORE_BINARY_I32(MaxI32U, "vm.max.i32.u");
     DISASM_OP_CORE_UNARY_I32(NotI32, "vm.not.i32");
     DISASM_OP_CORE_BINARY_I32(AndI32, "vm.and.i32");
     DISASM_OP_CORE_BINARY_I32(OrI32, "vm.or.i32");
@@ -1335,6 +1339,10 @@
     DISASM_OP_CORE_BINARY_I64(RemI64U, "vm.rem.i64.u");
     DISASM_OP_CORE_TERNARY_I64(FMAI64, "vm.fma.i64");
     DISASM_OP_CORE_UNARY_I64(AbsI64, "vm.abs.i64");
+    DISASM_OP_CORE_BINARY_I64(MinI64S, "vm.min.i64.s");
+    DISASM_OP_CORE_BINARY_I64(MinI64U, "vm.min.i64.u");
+    DISASM_OP_CORE_BINARY_I64(MaxI64S, "vm.max.i64.s");
+    DISASM_OP_CORE_BINARY_I64(MaxI64U, "vm.max.i64.u");
     DISASM_OP_CORE_UNARY_I64(NotI64, "vm.not.i64");
     DISASM_OP_CORE_BINARY_I64(AndI64, "vm.and.i64");
     DISASM_OP_CORE_BINARY_I64(OrI64, "vm.or.i64");
@@ -1939,6 +1947,9 @@
     DISASM_OP_EXT_F32_UNARY_F32(NegF32, "vm.neg.f32");
     DISASM_OP_EXT_F32_UNARY_F32(CeilF32, "vm.ceil.f32");
     DISASM_OP_EXT_F32_UNARY_F32(FloorF32, "vm.floor.f32");
+    DISASM_OP_EXT_F32_UNARY_F32(RoundF32, "vm.round.f32");
+    DISASM_OP_EXT_F32_BINARY_F32(MinF32, "vm.min.f32");
+    DISASM_OP_EXT_F32_BINARY_F32(MaxF32, "vm.max.f32");
 
     DISASM_OP_EXT_F32_UNARY_F32(AtanF32, "vm.atan.f32");
     DISASM_OP_EXT_F32_BINARY_F32(Atan2F32, "vm.atan2.f32");
diff --git a/runtime/src/iree/vm/bytecode/dispatch.c b/runtime/src/iree/vm/bytecode/dispatch.c
index 220f9c5..ff1744c 100644
--- a/runtime/src/iree/vm/bytecode/dispatch.c
+++ b/runtime/src/iree/vm/bytecode/dispatch.c
@@ -1428,6 +1428,10 @@
     DISPATCH_OP_CORE_BINARY_I32(RemI32U, vm_rem_i32u);
     DISPATCH_OP_CORE_TERNARY_I32(FMAI32, vm_fma_i32);
     DISPATCH_OP_CORE_UNARY_I32(AbsI32, vm_abs_i32);
+    DISPATCH_OP_CORE_BINARY_I32(MinI32S, vm_min_i32s);
+    DISPATCH_OP_CORE_BINARY_I32(MinI32U, vm_min_i32u);
+    DISPATCH_OP_CORE_BINARY_I32(MaxI32S, vm_max_i32s);
+    DISPATCH_OP_CORE_BINARY_I32(MaxI32U, vm_max_i32u);
     DISPATCH_OP_CORE_UNARY_I32(NotI32, vm_not_i32);
     DISPATCH_OP_CORE_BINARY_I32(AndI32, vm_and_i32);
     DISPATCH_OP_CORE_BINARY_I32(OrI32, vm_or_i32);
@@ -1443,6 +1447,10 @@
     DISPATCH_OP_CORE_BINARY_I64(RemI64U, vm_rem_i64u);
     DISPATCH_OP_CORE_TERNARY_I64(FMAI64, vm_fma_i64);
     DISPATCH_OP_CORE_UNARY_I64(AbsI64, vm_abs_i64);
+    DISPATCH_OP_CORE_BINARY_I64(MinI64S, vm_min_i64s);
+    DISPATCH_OP_CORE_BINARY_I64(MinI64U, vm_min_i64u);
+    DISPATCH_OP_CORE_BINARY_I64(MaxI64S, vm_max_i64s);
+    DISPATCH_OP_CORE_BINARY_I64(MaxI64U, vm_max_i64u);
     DISPATCH_OP_CORE_UNARY_I64(NotI64, vm_not_i64);
     DISPATCH_OP_CORE_BINARY_I64(AndI64, vm_and_i64);
     DISPATCH_OP_CORE_BINARY_I64(OrI64, vm_or_i64);
@@ -1926,6 +1934,8 @@
       DISPATCH_OP_EXT_F32_UNARY_F32(CeilF32, vm_ceil_f32);
       DISPATCH_OP_EXT_F32_UNARY_F32(FloorF32, vm_floor_f32);
       DISPATCH_OP_EXT_F32_UNARY_F32(RoundF32, vm_round_f32);
+      DISPATCH_OP_EXT_F32_BINARY_F32(MinF32, vm_min_f32);
+      DISPATCH_OP_EXT_F32_BINARY_F32(MaxF32, vm_max_f32);
 
       DISPATCH_OP_EXT_F32_UNARY_F32(AtanF32, vm_atan_f32);
       DISPATCH_OP_EXT_F32_BINARY_F32(Atan2F32, vm_atan2_f32);
diff --git a/runtime/src/iree/vm/bytecode/dispatch_test.cc b/runtime/src/iree/vm/bytecode/dispatch_test.cc
index c47df1b..d397611 100644
--- a/runtime/src/iree/vm/bytecode/dispatch_test.cc
+++ b/runtime/src/iree/vm/bytecode/dispatch_test.cc
@@ -102,7 +102,10 @@
         bytecode_module_, IREE_VM_FUNCTION_LINKAGE_EXPORT,
         iree_make_cstring_view(function_name), &function));
 
-    return iree_vm_invoke(context_, function, IREE_VM_INVOCATION_FLAG_NONE,
+    iree_vm_invocation_flags_t flags = IREE_VM_INVOCATION_FLAG_NONE;
+    // NOTE: adding this bit makes it easy to debug issues on stdout:
+    // flags |= IREE_VM_INVOCATION_FLAG_TRACE_EXECUTION;
+    return iree_vm_invoke(context_, function, flags,
                           /*policy=*/nullptr, /*inputs=*/nullptr,
                           /*outputs=*/nullptr, iree_allocator_system());
   }
diff --git a/runtime/src/iree/vm/bytecode/utils/generated/op_table.h b/runtime/src/iree/vm/bytecode/utils/generated/op_table.h
index 3ad3c5b..7fe629b 100644
--- a/runtime/src/iree/vm/bytecode/utils/generated/op_table.h
+++ b/runtime/src/iree/vm/bytecode/utils/generated/op_table.h
@@ -129,14 +129,14 @@
   IREE_VM_OP_CORE_AbsI32 = 0x77,
   IREE_VM_OP_CORE_AbsI64 = 0x78,
   IREE_VM_OP_CORE_Block = 0x79,
-  IREE_VM_OP_CORE_RSV_0x7A,
-  IREE_VM_OP_CORE_RSV_0x7B,
-  IREE_VM_OP_CORE_RSV_0x7C,
-  IREE_VM_OP_CORE_RSV_0x7D,
-  IREE_VM_OP_CORE_RSV_0x7E,
-  IREE_VM_OP_CORE_RSV_0x7F,
-  IREE_VM_OP_CORE_RSV_0x80,
-  IREE_VM_OP_CORE_RSV_0x81,
+  IREE_VM_OP_CORE_MinI32S = 0x7A,
+  IREE_VM_OP_CORE_MinI32U = 0x7B,
+  IREE_VM_OP_CORE_MaxI32S = 0x7C,
+  IREE_VM_OP_CORE_MaxI32U = 0x7D,
+  IREE_VM_OP_CORE_MinI64S = 0x7E,
+  IREE_VM_OP_CORE_MinI64U = 0x7F,
+  IREE_VM_OP_CORE_MaxI64S = 0x80,
+  IREE_VM_OP_CORE_MaxI64U = 0x81,
   IREE_VM_OP_CORE_RSV_0x82,
   IREE_VM_OP_CORE_RSV_0x83,
   IREE_VM_OP_CORE_RSV_0x84,
@@ -388,14 +388,14 @@
     OPC(0x77, AbsI32) \
     OPC(0x78, AbsI64) \
     OPC(0x79, Block) \
-    RSV(0x7A) \
-    RSV(0x7B) \
-    RSV(0x7C) \
-    RSV(0x7D) \
-    RSV(0x7E) \
-    RSV(0x7F) \
-    RSV(0x80) \
-    RSV(0x81) \
+    OPC(0x7A, MinI64S) \
+    OPC(0x7B, MinI64U) \
+    OPC(0x7C, MaxI64S) \
+    OPC(0x7D, MaxI64U) \
+    OPC(0x7E, MinI64S) \
+    OPC(0x7F, MinI64U) \
+    OPC(0x80, MaxI64S) \
+    OPC(0x81, MaxI64U) \
     RSV(0x82) \
     RSV(0x83) \
     RSV(0x84) \
@@ -579,8 +579,8 @@
   IREE_VM_OP_EXT_F32_BufferStoreF32 = 0x34,
   IREE_VM_OP_EXT_F32_BufferFillF32 = 0x35,
   IREE_VM_OP_EXT_F32_RoundF32 = 0x36,
-  IREE_VM_OP_EXT_F32_RSV_0x37,
-  IREE_VM_OP_EXT_F32_RSV_0x38,
+  IREE_VM_OP_EXT_F32_MinF32 = 0x37,
+  IREE_VM_OP_EXT_F32_MaxF32 = 0x38,
   IREE_VM_OP_EXT_F32_RSV_0x39,
   IREE_VM_OP_EXT_F32_RSV_0x3A,
   IREE_VM_OP_EXT_F32_RSV_0x3B,
@@ -838,8 +838,8 @@
     OPC(0x34, BufferStoreF32) \
     OPC(0x35, BufferFillF32) \
     OPC(0x36, RoundF32) \
-    RSV(0x37) \
-    RSV(0x38) \
+    OPC(0x37, MinF32) \
+    OPC(0x38, MaxF32) \
     RSV(0x39) \
     RSV(0x3A) \
     RSV(0x3B) \
@@ -1102,8 +1102,8 @@
   IREE_VM_OP_EXT_F64_BufferStoreF64 = 0x3A,
   IREE_VM_OP_EXT_F64_BufferFillF64 = 0x3B,
   IREE_VM_OP_EXT_F64_RoundF64 = 0x3C,
-  IREE_VM_OP_EXT_F64_RSV_0x3D,
-  IREE_VM_OP_EXT_F64_RSV_0x3E,
+  IREE_VM_OP_EXT_F64_MinF64 = 0x3D,
+  IREE_VM_OP_EXT_F64_MaxF64 = 0x3E,
   IREE_VM_OP_EXT_F64_RSV_0x3F,
   IREE_VM_OP_EXT_F64_RSV_0x40,
   IREE_VM_OP_EXT_F64_RSV_0x41,
@@ -1361,8 +1361,8 @@
     OPC(0x3A, BufferStoreF64) \
     OPC(0x3B, BufferFillF64) \
     OPC(0x3C, RoundF64) \
-    RSV(0x3D) \
-    RSV(0x3E) \
+    OPC(0x3D, MinF64) \
+    OPC(0x3E, MaxF64) \
     RSV(0x3F) \
     RSV(0x40) \
     RSV(0x41) \
diff --git a/runtime/src/iree/vm/bytecode/verifier.c b/runtime/src/iree/vm/bytecode/verifier.c
index f26c4f3..dfcf9ff 100644
--- a/runtime/src/iree/vm/bytecode/verifier.c
+++ b/runtime/src/iree/vm/bytecode/verifier.c
@@ -1392,6 +1392,10 @@
     VERIFY_OP_CORE_BINARY_I32(RemI32U);
     VERIFY_OP_CORE_TERNARY_I32(FMAI32);
     VERIFY_OP_CORE_UNARY_I32(AbsI32);
+    VERIFY_OP_CORE_BINARY_I32(MinI32S);
+    VERIFY_OP_CORE_BINARY_I32(MinI32U);
+    VERIFY_OP_CORE_BINARY_I32(MaxI32S);
+    VERIFY_OP_CORE_BINARY_I32(MaxI32U);
     VERIFY_OP_CORE_UNARY_I32(NotI32);
     VERIFY_OP_CORE_BINARY_I32(AndI32);
     VERIFY_OP_CORE_BINARY_I32(OrI32);
@@ -1407,6 +1411,10 @@
     VERIFY_OP_CORE_BINARY_I64(RemI64U);
     VERIFY_OP_CORE_TERNARY_I64(FMAI64);
     VERIFY_OP_CORE_UNARY_I64(AbsI64);
+    VERIFY_OP_CORE_BINARY_I64(MinI64S);
+    VERIFY_OP_CORE_BINARY_I64(MinI64U);
+    VERIFY_OP_CORE_BINARY_I64(MaxI64S);
+    VERIFY_OP_CORE_BINARY_I64(MaxI64U);
     VERIFY_OP_CORE_UNARY_I64(NotI64);
     VERIFY_OP_CORE_BINARY_I64(AndI64);
     VERIFY_OP_CORE_BINARY_I64(OrI64);
@@ -1748,6 +1756,8 @@
     VERIFY_OP_EXT_F32_UNARY_F32(CeilF32);
     VERIFY_OP_EXT_F32_UNARY_F32(FloorF32);
     VERIFY_OP_EXT_F32_UNARY_F32(RoundF32);
+    VERIFY_OP_EXT_F32_BINARY_F32(MinF32);
+    VERIFY_OP_EXT_F32_BINARY_F32(MaxF32);
 
     VERIFY_OP_EXT_F32_UNARY_F32(AtanF32);
     VERIFY_OP_EXT_F32_BINARY_F32(Atan2F32);
diff --git a/runtime/src/iree/vm/ops.h b/runtime/src/iree/vm/ops.h
index 1bfffbd..0137f2c 100644
--- a/runtime/src/iree/vm/ops.h
+++ b/runtime/src/iree/vm/ops.h
@@ -256,6 +256,18 @@
   return a * b + c;
 }
 static inline int32_t vm_abs_i32(int32_t operand) { return abs(operand); }
+static inline int32_t vm_min_i32s(int32_t lhs, int32_t rhs) {
+  return rhs < lhs ? rhs : lhs;
+}
+static inline int32_t vm_min_i32u(int32_t lhs, int32_t rhs) {
+  return (uint32_t)rhs < (uint32_t)lhs ? rhs : lhs;
+}
+static inline int32_t vm_max_i32s(int32_t lhs, int32_t rhs) {
+  return lhs < rhs ? rhs : lhs;
+}
+static inline int32_t vm_max_i32u(int32_t lhs, int32_t rhs) {
+  return (uint32_t)lhs < (uint32_t)rhs ? rhs : lhs;
+}
 static inline int32_t vm_not_i32(int32_t operand) {
   return (int32_t)(~((uint32_t)operand));
 }
@@ -382,6 +394,18 @@
   return a * b + c;
 }
 static inline int64_t vm_abs_i64(int64_t operand) { return labs(operand); }
+static inline int64_t vm_min_i64s(int64_t lhs, int64_t rhs) {
+  return rhs < lhs ? rhs : lhs;
+}
+static inline int64_t vm_min_i64u(int64_t lhs, int64_t rhs) {
+  return (uint64_t)rhs < (uint64_t)lhs ? rhs : lhs;
+}
+static inline int64_t vm_max_i64s(int64_t lhs, int64_t rhs) {
+  return lhs < rhs ? rhs : lhs;
+}
+static inline int64_t vm_max_i64u(int64_t lhs, int64_t rhs) {
+  return (uint64_t)lhs < (uint64_t)rhs ? rhs : lhs;
+}
 static inline int64_t vm_not_i64(int64_t operand) {
   return (int64_t)(~((uint64_t)operand));
 }
@@ -527,6 +551,12 @@
 static inline float vm_ceil_f32(float operand) { return ceilf(operand); }
 static inline float vm_floor_f32(float operand) { return floorf(operand); }
 static inline float vm_round_f32(float operand) { return roundf(operand); }
+static inline float vm_min_f32(float lhs, float rhs) {
+  return rhs < lhs ? rhs : lhs;
+}
+static inline float vm_max_f32(float lhs, float rhs) {
+  return lhs < rhs ? rhs : lhs;
+}
 
 static inline float vm_atan_f32(float operand) { return atanf(operand); }
 static inline float vm_atan2_f32(float y, float x) { return atan2f(y, x); }
diff --git a/runtime/src/iree/vm/test/arithmetic_ops.mlir b/runtime/src/iree/vm/test/arithmetic_ops.mlir
index 9046b6b..4ec12e1 100644
--- a/runtime/src/iree/vm/test/arithmetic_ops.mlir
+++ b/runtime/src/iree/vm/test/arithmetic_ops.mlir
@@ -100,11 +100,55 @@
 
   vm.export @test_abs_i32
   vm.func @test_abs_i32() {
-    %c1 = vm.const.i32 -1
-    %c1dno = util.optimization_barrier %c1 : i32
-    %v = vm.abs.i32 %c1dno : i32
-    %c2 = vm.const.i32 1
-    vm.check.eq %v, %c2, "abs(-1)=1" : i32
+    %cn1 = vm.const.i32 -1
+    %cn1dno = util.optimization_barrier %cn1 : i32
+    %v = vm.abs.i32 %cn1dno : i32
+    %c1 = vm.const.i32 1
+    vm.check.eq %v, %c1, "abs(-1)=1" : i32
+    vm.return
+  }
+
+  vm.export @test_min_i32s
+  vm.func @test_min_i32s() {
+    %cn3 = vm.const.i32 -3
+    %cn3dno = util.optimization_barrier %cn3 : i32
+    %c2 = vm.const.i32 2
+    %c2dno = util.optimization_barrier %c2 : i32
+    %v = vm.min.i32.s %cn3dno, %c2dno : i32
+    vm.check.eq %v, %cn3, "smin(-3,2)=-3" : i32
+    vm.return
+  }
+
+  vm.export @test_min_i32u
+  vm.func @test_min_i32u() {
+    %cn3 = vm.const.i32 -3
+    %cn3dno = util.optimization_barrier %cn3 : i32
+    %c2 = vm.const.i32 2
+    %c2dno = util.optimization_barrier %c2 : i32
+    %v = vm.min.i32.u %cn3dno, %c2dno : i32
+    vm.check.eq %v, %c2, "umin(-3,2)=2" : i32
+    vm.return
+  }
+
+  vm.export @test_max_i32s
+  vm.func @test_max_i32s() {
+    %cn3 = vm.const.i32 -3
+    %cn3dno = util.optimization_barrier %cn3 : i32
+    %c2 = vm.const.i32 2
+    %c2dno = util.optimization_barrier %c2 : i32
+    %v = vm.max.i32.s %cn3dno, %c2dno : i32
+    vm.check.eq %v, %c2, "smax(-3,2)=2" : i32
+    vm.return
+  }
+
+  vm.export @test_max_i32u
+  vm.func @test_max_i32u() {
+    %cn3 = vm.const.i32 -3
+    %cn3dno = util.optimization_barrier %cn3 : i32
+    %c2 = vm.const.i32 2
+    %c2dno = util.optimization_barrier %c2 : i32
+    %v = vm.max.i32.u %cn3dno, %c2dno : i32
+    vm.check.eq %v, %cn3, "umax(-3,2)=-3" : i32
     vm.return
   }
 
diff --git a/runtime/src/iree/vm/test/arithmetic_ops_f32.mlir b/runtime/src/iree/vm/test/arithmetic_ops_f32.mlir
index ce478fb..f446f4d 100644
--- a/runtime/src/iree/vm/test/arithmetic_ops_f32.mlir
+++ b/runtime/src/iree/vm/test/arithmetic_ops_f32.mlir
@@ -106,11 +106,43 @@
 
   vm.export @test_floor_f32
   vm.func @test_floor_f32() {
-    %c1 = vm.const.f32 1.5
-    %c1dno = util.optimization_barrier %c1 : f32
-    %v = vm.floor.f32 %c1dno : f32
-    %c2 = vm.const.f32 1.0
-    vm.check.eq %v, %c2, "floor(1.5)=1.0" : f32
+    %c15 = vm.const.f32 1.5
+    %c15dno = util.optimization_barrier %c15 : f32
+    %v = vm.floor.f32 %c15dno : f32
+    %c1 = vm.const.f32 1.0
+    vm.check.eq %v, %c1, "floor(1.5)=1.0" : f32
+    vm.return
+  }
+
+  vm.export @test_round_f32
+  vm.func @test_round_f32() {
+    %c15 = vm.const.f32 1.5
+    %c15dno = util.optimization_barrier %c15 : f32
+    %v = vm.round.f32 %c15dno : f32
+    %c2 = vm.const.f32 2.0
+    vm.check.eq %v, %c2, "round(1.5)=2.0" : f32
+    vm.return
+  }
+
+  vm.export @test_min_f32
+  vm.func @test_min_f32() {
+    %cn3 = vm.const.f32 -3.0
+    %cn3dno = util.optimization_barrier %cn3 : f32
+    %cn2 = vm.const.f32 -2.0
+    %cn2dno = util.optimization_barrier %cn2 : f32
+    %v = vm.min.f32 %cn3dno, %cn2dno : f32
+    vm.check.eq %v, %cn3, "min(-3.0,-2.0)=-3.0" : f32
+    vm.return
+  }
+
+  vm.export @test_max_f32
+  vm.func @test_max_f32() {
+    %cn3 = vm.const.f32 -3.0
+    %cn3dno = util.optimization_barrier %cn3 : f32
+    %cn2 = vm.const.f32 -2.0
+    %cn2dno = util.optimization_barrier %cn2 : f32
+    %v = vm.max.f32 %cn3dno, %cn2dno : f32
+    vm.check.eq %v, %cn2, "max(-3.0,-2.0)=-2.0" : f32
     vm.return
   }
 
diff --git a/runtime/src/iree/vm/test/arithmetic_ops_i64.mlir b/runtime/src/iree/vm/test/arithmetic_ops_i64.mlir
index fd75c60..b6cc8a2 100644
--- a/runtime/src/iree/vm/test/arithmetic_ops_i64.mlir
+++ b/runtime/src/iree/vm/test/arithmetic_ops_i64.mlir
@@ -100,11 +100,55 @@
 
   vm.export @test_abs_i64
   vm.func @test_abs_i64() {
-    %c1 = vm.const.i64 -1
-    %c1dno = util.optimization_barrier %c1 : i64
-    %v = vm.abs.i64 %c1dno : i64
-    %c2 = vm.const.i64 1
-    vm.check.eq %v, %c2, "abs(-1)=1" : i64
+    %cn1 = vm.const.i64 -1
+    %cn1dno = util.optimization_barrier %cn1 : i64
+    %v = vm.abs.i64 %cn1dno : i64
+    %c1 = vm.const.i64 1
+    vm.check.eq %v, %c1, "abs(-1)=1" : i64
+    vm.return
+  }
+
+  vm.export @test_min_i64s
+  vm.func @test_min_i64s() {
+    %cn3 = vm.const.i64 -3
+    %cn3dno = util.optimization_barrier %cn3 : i64
+    %c2 = vm.const.i64 2
+    %c2dno = util.optimization_barrier %c2 : i64
+    %v = vm.min.i64.s %cn3dno, %c2dno : i64
+    vm.check.eq %v, %cn3, "smin(-3,2)=-3" : i64
+    vm.return
+  }
+
+  vm.export @test_min_i64u
+  vm.func @test_min_i64u() {
+    %cn3 = vm.const.i64 -3
+    %cn3dno = util.optimization_barrier %cn3 : i64
+    %c2 = vm.const.i64 2
+    %c2dno = util.optimization_barrier %c2 : i64
+    %v = vm.min.i64.u %cn3dno, %c2dno : i64
+    vm.check.eq %v, %c2, "umin(-3,2)=2" : i64
+    vm.return
+  }
+
+  vm.export @test_max_i64s
+  vm.func @test_max_i64s() {
+    %cn3 = vm.const.i64 -3
+    %cn3dno = util.optimization_barrier %cn3 : i64
+    %c2 = vm.const.i64 2
+    %c2dno = util.optimization_barrier %c2 : i64
+    %v = vm.max.i64.s %cn3dno, %c2dno : i64
+    vm.check.eq %v, %c2, "smax(-3,2)=2" : i64
+    vm.return
+  }
+
+  vm.export @test_max_i64u
+  vm.func @test_max_i64u() {
+    %cn3 = vm.const.i64 -3
+    %cn3dno = util.optimization_barrier %cn3 : i64
+    %c2 = vm.const.i64 2
+    %c2dno = util.optimization_barrier %c2 : i64
+    %v = vm.max.i64.u %cn3dno, %c2dno : i64
+    vm.check.eq %v, %cn3, "umax(-3,2)=-3" : i64
     vm.return
   }