Swapping from abseil flags to IREE flags.
This allows us to remove the nasty --function_inputs in favor of
a repeated --function_input field.
diff --git a/bindings/python/iree/jax/README.md b/bindings/python/iree/jax/README.md
index 557cfee..a4fac75 100644
--- a/bindings/python/iree/jax/README.md
+++ b/bindings/python/iree/jax/README.md
@@ -95,8 +95,12 @@
 adb push /tmp/mlp_apply.vmfb /data/local/tmp/
 adb push ../iree-build-android/iree/tools/iree-run-module /data/local/tmp/
 adb shell /data/local/tmp/iree-run-module \
-  -module_file=/data/local/tmp/mlp_apply.vmfb \
-  -function_inputs="128xf32,784x128xf32,10xf32,128x10xf32,1x28x28x1xf32" \
-  -driver=dylib \
-  -entry_function=main
+  --driver=dylib \
+  --module_file=/data/local/tmp/mlp_apply.vmfb \
+  --entry_function=main \
+  --function_input=128xf32 \
+  --function_input=784x128xf32 \
+  --function_input=10xf32 \
+  --function_input=128x10xf32 \
+  --function_input=1x28x28x1xf32
 ```
diff --git a/docs/design_docs/cuda_backend.md b/docs/design_docs/cuda_backend.md
index 5b84c25..eb0cac4 100644
--- a/docs/design_docs/cuda_backend.md
+++ b/docs/design_docs/cuda_backend.md
@@ -79,15 +79,18 @@
 # First translate into a VM bytecode module using linalg on tensors path.
 $ ../iree-build/iree/tools/iree-translate \
  -iree-mlir-to-vm-bytecode-module \
- --iree-hal-target-backends=cuda \
+ -iree-hal-target-backends=cuda \
  -iree-flow-dispatch-linalg-on-tensors \
  /tmp/add.mlir \
  -o /tmp/mhlo-add.vmfb
 
 # Run the module through CUDA HAL backend.
 $ ../iree-build/iree/tools/iree-run-module \
--module_file=/tmp/mhlo-add.vmfb -driver=cuda -entry_function=add \
---function_inputs='4xf32=[1 2 3 4], 4xf32=[2 2 2 2]'
+  --driver=cuda \
+  --module_file=/tmp/mhlo-add.vmfb \
+  --entry_function=add \
+  --function_input="4xf32=[1 2 3 4]" \
+  --function_input="4xf32=[2 2 2 2]"
 
 EXEC @add
 4xf32=3 4 5 6
diff --git a/docs/developing_iree/benchmarking.md b/docs/developing_iree/benchmarking.md
index b203c62..6956b67 100644
--- a/docs/developing_iree/benchmarking.md
+++ b/docs/developing_iree/benchmarking.md
@@ -33,7 +33,7 @@
   --module_file=/tmp/module.fb \
   --driver=vmla \
   --entry_function=abs \
-  --function_inputs="i32=-2"
+  --function_input=i32=-2
 ```
 
 You'll see output like
@@ -80,7 +80,7 @@
   --module_file=/tmp/module.fb \
   --driver=vmla \
   --entry_function=abs \
-  --function_inputs="i32=-2"
+  --function_input=i32=-2
 ```
 
 ```shell
diff --git a/docs/developing_iree/developer_overview.md b/docs/developing_iree/developer_overview.md
index 13a3b69..e0caae5 100644
--- a/docs/developing_iree/developer_overview.md
+++ b/docs/developing_iree/developer_overview.md
@@ -141,7 +141,7 @@
   --module_file=/tmp/simple.vmfb \
   --driver=vmla \
   --entry_function=abs \
-  --function_inputs="i32=-2"
+  --function_input=i32=-2
 ```
 
 ### iree-check-module
diff --git a/docs/developing_iree/profiling_vulkan_gpu.md b/docs/developing_iree/profiling_vulkan_gpu.md
index b9421f0..8fb76b5 100644
--- a/docs/developing_iree/profiling_vulkan_gpu.md
+++ b/docs/developing_iree/profiling_vulkan_gpu.md
@@ -45,10 +45,10 @@
 # Then package the Android app
 $ /path/to/iree/source/iree/tools/android/run_module_app/build_apk.sh \
   ./build-apk \
+  --driver vulkan \
   --module_file /tmp/mhlo-dot.vmfb \
   --entry_function dot \
-  --function_inputs_file /path/to/inputs/file \
-  --driver vulkan
+  --function_input=...
 ```
 
 Where `/path/to/input/file` is a file containing inputs to `dot`, for example:
diff --git a/docs/developing_iree/profiling_with_tracy.md b/docs/developing_iree/profiling_with_tracy.md
index 4d5c58f..528d731 100644
--- a/docs/developing_iree/profiling_with_tracy.md
+++ b/docs/developing_iree/profiling_with_tracy.md
@@ -137,9 +137,11 @@
 ```shell
 TRACY_NO_EXIT=1 /data/local/tmp/iree-benchmark-module \
   --driver=dylib \
-  --function_inputs='1x384xi32,1x384xi32,1x384xi32' \
   --module_file=/data/local/tmp/android_module.fbvm \
-  --entry_function=serving_default
+  --entry_function=serving_default \
+  --function_input=1x384xi32 \
+  --function_input=1x384xi32 \
+  --function_input=1x384xi32
 ```
 
 ## Running the Tracy profiler UI, connecting and visualizing
diff --git a/docs/get_started/getting_started_android_cmake.md b/docs/get_started/getting_started_android_cmake.md
index 2420f83..8928f11 100644
--- a/docs/get_started/getting_started_android_cmake.md
+++ b/docs/get_started/getting_started_android_cmake.md
@@ -164,10 +164,11 @@
 $ adb shell
 
 android $ cd /data/local/tmp/
-android $ ./iree-run-module -driver=vmla \
-          -module_file=simple-vmla.vmfb \
-          -entry_function=abs \
-          -function_inputs="i32=-5"
+android $ ./iree-run-module \
+          --driver=vmla \
+          --module_file=simple-vmla.vmfb \
+          --entry_function=abs \
+          --function_input=i32=-5
 
 EXEC @abs
 i32=5
@@ -202,10 +203,11 @@
 $ adb shell
 
 android $ cd /data/local/tmp/
-android $ ./iree-run-module -driver=vulkan \
-          -module_file=simple-vulkan.vmfb \
-          -entry_function=abs \
-          -function_inputs="i32=-5"
+android $ ./iree-run-module \
+          --driver=vulkan \
+          --module_file=simple-vulkan.vmfb \
+          --entry_function=abs \
+          --function_input=i32=-5
 
 EXEC @abs
 i32=5
@@ -279,10 +281,11 @@
 $ adb shell
 
 android $ cd /data/local/tmp/
-android $ ./iree-run-module -driver=dylib \
-          -module_file=simple-llvm_aot.vmfb \
-          -entry_function=abs \
-          -function_inputs="i32=-5"
+android $ ./iree-run-module \
+          --driver=dylib \
+          --module_file=simple-llvm_aot.vmfb \
+          --entry_function=abs \
+          --function_input=i32=-5
 
 EXEC @abs
 i32=5
diff --git a/docs/get_started/getting_started_linux_cmake.md b/docs/get_started/getting_started_linux_cmake.md
index c0ec8d2..92a3dfd 100644
--- a/docs/get_started/getting_started_linux_cmake.md
+++ b/docs/get_started/getting_started_linux_cmake.md
@@ -131,10 +131,11 @@
 Then run the compiled module using the `dylib` HAL driver:
 
 ```shell
-$ ../iree-build/iree/tools/iree-run-module -driver=dylib \
-    -module_file=/tmp/simple-llvm_aot.vmfb \
-    -entry_function=abs \
-    -function_inputs="i32=-5"
+$ ../iree-build/iree/tools/iree-run-module \
+    --driver=dylib \
+    --module_file=/tmp/simple-llvm_aot.vmfb \
+    --entry_function=abs \
+    --function_input=i32=-5
 
 EXEC @abs
 i32=5
diff --git a/docs/get_started/getting_started_linux_vulkan.md b/docs/get_started/getting_started_linux_vulkan.md
index c4ee13d..1264297 100644
--- a/docs/get_started/getting_started_linux_vulkan.md
+++ b/docs/get_started/getting_started_linux_vulkan.md
@@ -134,10 +134,18 @@
 ```shell
 # -- CMake --
 $ cmake --build ../iree-build/ --target iree_tools_iree-run-module
-$ ../iree-build/iree/tools/iree-run-module -module_file=/tmp/module.vmfb -driver=vulkan -entry_function=abs -function_inputs="i32=-2"
+$ ../iree-build/iree/tools/iree-run-module \
+    --driver=vulkan \
+    --module_file=/tmp/module.vmfb \
+    --entry_function=abs \
+    --function_input=i32=-2
 
 # -- Bazel --
-$ bazel run iree/tools:iree-run-module -- -module_file=/tmp/module.vmfb -driver=vulkan -entry_function=abs -function_inputs="i32=-2"
+$ bazel run iree/tools:iree-run-module -- \
+    --driver=vulkan \
+    --module_file=/tmp/module.vmfb \
+    --entry_function=abs \
+    --function_input=i32=-2
 ```
 
 ## Running IREE's Vulkan Samples
diff --git a/docs/get_started/getting_started_riscv_cmake.md b/docs/get_started/getting_started_riscv_cmake.md
index 276ca73..0e50fd0 100644
--- a/docs/get_started/getting_started_riscv_cmake.md
+++ b/docs/get_started/getting_started_riscv_cmake.md
@@ -104,10 +104,11 @@
 $ $HOME/riscv/qemu/linux/RISCV/bin/qemu-riscv64 \
   -cpu rv64,x-v=true,x-k=true,vlen=256,elen=64,vext_spec=v1.0 \
   -L $HOME/riscv/toolchain/clang/linux/RISCV/sysroot/ \
-  ../iree-build-riscv/iree/tools/iree-run-module -driver=vmla \
-  -module_file=/tmp/iree-run-module-vmla.vmfb \
-  -entry_function=abs \
-  -function_inputs="i32=-5"
+  ../iree-build-riscv/iree/tools/iree-run-module \
+  --driver=vmla \
+  --module_file=/tmp/iree-run-module-vmla.vmfb \
+  --entry_function=abs \
+  --function_input=i32=-5
 ```
 
 Output:
@@ -147,10 +148,11 @@
 $ $HOME/riscv/qemu/linux/RISCV/bin/qemu-riscv64 \
   -cpu rv64 \
   -L $HOME/riscv/toolchain/clang/linux/RISCV/sysroot/ \
-  ../iree-build-riscv/iree/tools/iree-run-module -driver=dylib \
-  -module_file=/tmp/iree-run-module-llvm_aot.vmfb \
-  -entry_function=abs \
-  -function_inputs="i32=-5"
+  ../iree-build-riscv/iree/tools/iree-run-module \
+  --driver=dylib \
+  --module_file=/tmp/iree-run-module-llvm_aot.vmfb \
+  --entry_function=abs \
+  --function_input=i32=-5
 ```
 
 Output:
diff --git a/docs/get_started/getting_started_windows_vulkan.md b/docs/get_started/getting_started_windows_vulkan.md
index cb19e21..4b37faa 100644
--- a/docs/get_started/getting_started_windows_vulkan.md
+++ b/docs/get_started/getting_started_windows_vulkan.md
@@ -132,10 +132,18 @@
 ```powershell
 # -- CMake --
 > cmake --build ..\iree-build\ --target iree_tools_iree-run-module
-> ..\iree-build\iree\tools\iree-run-module.exe -module_file=.\build\module.vmfb -driver=vulkan -entry_function=abs -function_inputs="i32=-2"
+> ..\iree-build\iree\tools\iree-run-module.exe \
+    --driver=vulkan \
+    --module_file=.\build\module.vmfb \
+    --entry_function=abs \
+    --function_input=i32=-2
 
 # -- Bazel --
-> bazel run iree/tools:iree-run-module -- -module_file=.\build\module.vmfb -driver=vulkan -entry_function=abs -function_inputs="i32=-2"
+> bazel run iree/tools:iree-run-module -- \
+    --driver=vulkan \
+    --module_file=.\build\module.vmfb \
+    --entry_function=abs \
+    --function_input=i32=-2
 ```
 
 ## Running IREE's Vulkan Samples
diff --git a/integrations/tensorflow/bindings/python/iree/tf/support/trace_utils.py b/integrations/tensorflow/bindings/python/iree/tf/support/trace_utils.py
index f5ae8d3..5fa7eab 100644
--- a/integrations/tensorflow/bindings/python/iree/tf/support/trace_utils.py
+++ b/integrations/tensorflow/bindings/python/iree/tf/support/trace_utils.py
@@ -291,13 +291,12 @@
       compiled_path = self.compiled_paths[entry_function]
 
       if self.iree_serializable:
-        serialized_inputs = ", ".join(self.calls[0].serialized_inputs)
+        serialized_inputs = self.calls[0].serialized_inputs
         flagfile = [
             f"--module_file={compiled_path}",
             f"--driver={self.backend_driver}",
-            f"--function_inputs={serialized_inputs}",
             f"--entry_function={entry_function}",
-        ]
+        ] + [f"--function_input={input}" for input in serialized_inputs]
         with open(os.path.join(trace_dir, "flagfile"), "w") as f:
           f.writelines(line + "\n" for line in flagfile)
       else:
diff --git a/iree/base/BUILD b/iree/base/BUILD
index c016606..40423fc 100644
--- a/iree/base/BUILD
+++ b/iree/base/BUILD
@@ -99,7 +99,7 @@
     deps = [
         ":core_headers",
         ":tracing",
-        "@com_google_absl//absl/flags:flag",
+        "//iree/base/internal:flags",
         "@com_google_absl//absl/strings:str_format",
     ],
 )
diff --git a/iree/base/CMakeLists.txt b/iree/base/CMakeLists.txt
index a9e26ea..54ecc4b 100644
--- a/iree/base/CMakeLists.txt
+++ b/iree/base/CMakeLists.txt
@@ -84,8 +84,8 @@
   DEPS
     ::core_headers
     ::tracing
-    absl::flags
     absl::str_format
+    iree::base::internal::flags
   PUBLIC
 )
 
diff --git a/iree/base/logging.cc b/iree/base/logging.cc
index a8ecd73..eaacb99 100644
--- a/iree/base/logging.cc
+++ b/iree/base/logging.cc
@@ -20,13 +20,13 @@
 #include <android/log.h>
 #endif
 
-#include "absl/flags/flag.h"
 #include "absl/strings/str_format.h"
+#include "iree/base/internal/flags.h"
 #include "iree/base/tracing.h"
 
-ABSL_FLAG(int, iree_minloglevel, 0,
+IREE_FLAG(int32_t, iree_minloglevel, 0,
           "Minimum logging level. 0 = INFO and above.");
-ABSL_FLAG(int, iree_v, 0,
+IREE_FLAG(int32_t, iree_v, 0,
           "Verbosity level maximum. 1 = IREE_VLOG(0-1), 2 = IREE_VLOG(0-2).");
 
 namespace iree {
@@ -60,7 +60,7 @@
   if (LogLevelStrToInt(iree_env_var_val, &level)) {
     return level;
   }
-  return absl::GetFlag(FLAGS_iree_minloglevel);
+  return FLAG_iree_minloglevel;
 }
 
 int64_t MinVLogLevelFromEnv() {
@@ -69,7 +69,7 @@
   if (LogLevelStrToInt(iree_env_var_val, &level)) {
     return level;
   }
-  return absl::GetFlag(FLAGS_iree_v);
+  return FLAG_iree_v;
 }
 
 }  // namespace
diff --git a/iree/hal/dylib/registration/BUILD b/iree/hal/dylib/registration/BUILD
index 565906a..6a48016 100644
--- a/iree/hal/dylib/registration/BUILD
+++ b/iree/hal/dylib/registration/BUILD
@@ -37,11 +37,11 @@
         "IREE_HAL_HAVE_DYLIB_DRIVER_MODULE=1",
     ],
     deps = [
+        "//iree/base/internal:flags",
         "//iree/hal:api",
         "//iree/hal/local:task_driver",
         "//iree/hal/local/loaders:embedded_library_loader",
         "//iree/hal/local/loaders:legacy_library_loader",
-        "@com_google_absl//absl/flags:flag",
     ],
 )
 
diff --git a/iree/hal/dylib/registration/CMakeLists.txt b/iree/hal/dylib/registration/CMakeLists.txt
index 2b7953c..8997c79 100644
--- a/iree/hal/dylib/registration/CMakeLists.txt
+++ b/iree/hal/dylib/registration/CMakeLists.txt
@@ -22,7 +22,7 @@
   SRCS
     "driver_module.cc"
   DEPS
-    absl::flags
+    iree::base::internal::flags
     iree::hal::api
     iree::hal::local::loaders::embedded_library_loader
     iree::hal::local::loaders::legacy_library_loader
diff --git a/iree/hal/dylib/registration/driver_module.cc b/iree/hal/dylib/registration/driver_module.cc
index f529c71..18b35ac 100644
--- a/iree/hal/dylib/registration/driver_module.cc
+++ b/iree/hal/dylib/registration/driver_module.cc
@@ -16,7 +16,7 @@
 
 #include <inttypes.h>
 
-#include "absl/flags/flag.h"
+#include "iree/base/internal/flags.h"
 #include "iree/hal/local/loaders/embedded_library_loader.h"
 #include "iree/hal/local/loaders/legacy_library_loader.h"
 #include "iree/hal/local/task_driver.h"
@@ -28,9 +28,9 @@
 // using an existing executor so that we can entirely externalize the task
 // system configuration from the HAL.
 
-ABSL_FLAG(int, dylib_worker_count, 0,
+IREE_FLAG(int32_t, dylib_worker_count, 0,
           "Specified number of workers to use or 0 for automatic.");
-ABSL_FLAG(int, dylib_max_worker_count, 16,
+IREE_FLAG(int32_t, dylib_max_worker_count, 16,
           "Maximum number of task system workers to use.");
 
 #define IREE_HAL_DYLIB_DRIVER_ID 0x58444C4Cu  // XDLL
@@ -66,13 +66,12 @@
 
   iree_task_topology_t topology;
   iree_task_topology_initialize(&topology);
-  if (absl::GetFlag(FLAGS_dylib_worker_count) > 0) {
-    iree_task_topology_initialize_from_group_count(
-        absl::GetFlag(FLAGS_dylib_worker_count), &topology);
+  if (FLAG_dylib_worker_count > 0) {
+    iree_task_topology_initialize_from_group_count(FLAG_dylib_worker_count,
+                                                   &topology);
   } else {
     iree_task_topology_initialize_from_unique_l2_cache_groups(
-        /*max_group_count=*/absl::GetFlag(FLAGS_dylib_max_worker_count),
-        &topology);
+        /*max_group_count=*/FLAG_dylib_max_worker_count, &topology);
   }
 
   iree_status_t status = iree_ok_status();
diff --git a/iree/hal/vulkan/registration/BUILD b/iree/hal/vulkan/registration/BUILD
index c8e40ac..a7a645a 100644
--- a/iree/hal/vulkan/registration/BUILD
+++ b/iree/hal/vulkan/registration/BUILD
@@ -41,7 +41,6 @@
         "//iree/base/internal:flags",
         "//iree/hal:api",
         "//iree/hal/vulkan",
-        "@com_google_absl//absl/flags:flag",
     ],
 )
 
diff --git a/iree/hal/vulkan/registration/CMakeLists.txt b/iree/hal/vulkan/registration/CMakeLists.txt
index 51c41bc..87ddb12 100644
--- a/iree/hal/vulkan/registration/CMakeLists.txt
+++ b/iree/hal/vulkan/registration/CMakeLists.txt
@@ -20,7 +20,6 @@
   SRCS
     "driver_module.cc"
   DEPS
-    absl::flags
     iree::base::core_headers
     iree::base::internal::flags
     iree::base::status
diff --git a/iree/hal/vulkan/registration/driver_module.cc b/iree/hal/vulkan/registration/driver_module.cc
index 761943b..2d3faf0 100644
--- a/iree/hal/vulkan/registration/driver_module.cc
+++ b/iree/hal/vulkan/registration/driver_module.cc
@@ -16,7 +16,6 @@
 
 #include <inttypes.h>
 
-#include "absl/flags/flag.h"
 #include "iree/base/internal/flags.h"
 #include "iree/base/status.h"
 #include "iree/base/target_platform.h"
@@ -25,17 +24,18 @@
 
 #define IREE_HAL_VULKAN_1_X_DRIVER_ID 0x564C4B31u  // VLK1
 
-ABSL_FLAG(bool, vulkan_validation_layers, true,
+IREE_FLAG(bool, vulkan_validation_layers, true,
           "Enables standard Vulkan validation layers.");
-ABSL_FLAG(bool, vulkan_debug_utils, true,
+IREE_FLAG(bool, vulkan_debug_utils, true,
           "Enables VK_EXT_debug_utils, records markers, and logs errors.");
 
-ABSL_FLAG(int, vulkan_default_index, 0, "Index of the default Vulkan device.");
+IREE_FLAG(int32_t, vulkan_default_index, 0,
+          "Index of the default Vulkan device.");
 
-ABSL_FLAG(bool, vulkan_force_timeline_semaphore_emulation, false,
+IREE_FLAG(bool, vulkan_force_timeline_semaphore_emulation, false,
           "Uses timeline semaphore emulation even if native support exists.");
 
-ABSL_FLAG(bool, vulkan_tracing, true,
+IREE_FLAG(bool, vulkan_tracing, true,
           "Enables Vulkan tracing (if IREE tracing is enabled).");
 
 static iree_status_t iree_hal_vulkan_create_driver_with_flags(
@@ -58,22 +58,21 @@
   driver_options.api_version = VK_API_VERSION_1_2;
 #endif  // IREE_PLATFORM_ANDROID
 
-  if (absl::GetFlag(FLAGS_vulkan_validation_layers)) {
+  if (FLAG_vulkan_validation_layers) {
     driver_options.requested_features |=
         IREE_HAL_VULKAN_FEATURE_ENABLE_VALIDATION_LAYERS;
   }
-  if (absl::GetFlag(FLAGS_vulkan_debug_utils)) {
+  if (FLAG_vulkan_debug_utils) {
     driver_options.requested_features |=
         IREE_HAL_VULKAN_FEATURE_ENABLE_DEBUG_UTILS;
   }
-  if (absl::GetFlag(FLAGS_vulkan_tracing)) {
+  if (FLAG_vulkan_tracing) {
     driver_options.requested_features |= IREE_HAL_VULKAN_FEATURE_ENABLE_TRACING;
   }
 
-  driver_options.default_device_index =
-      absl::GetFlag(FLAGS_vulkan_default_index);
+  driver_options.default_device_index = FLAG_vulkan_default_index;
 
-  if (absl::GetFlag(FLAGS_vulkan_force_timeline_semaphore_emulation)) {
+  if (FLAG_vulkan_force_timeline_semaphore_emulation) {
     driver_options.device_options.flags |=
         IREE_HAL_VULKAN_DEVICE_FORCE_TIMELINE_SEMAPHORE_EMULATION;
   }
diff --git a/iree/testing/benchmark_main.c b/iree/testing/benchmark_main.c
index 2fcf14b..82e64d6 100644
--- a/iree/testing/benchmark_main.c
+++ b/iree/testing/benchmark_main.c
@@ -16,8 +16,26 @@
 #include "iree/testing/benchmark.h"
 
 int main(int argc, char** argv) {
+  // Pass through flags to benchmark.
+  // Note that we handle --help so we have to include benchmark's flags here.
+  iree_flags_set_usage(
+      NULL,
+      "\n\n"
+      "  Optional flags from third_party/benchmark/src/benchmark.cc:\n"
+      "    [--benchmark_list_tests={true|false}]\n"
+      "    [--benchmark_filter=<regex>]\n"
+      "    [--benchmark_min_time=<min_time>]\n"
+      "    [--benchmark_repetitions=<num_repetitions>]\n"
+      "    [--benchmark_report_aggregates_only={true|false}]\n"
+      "    [--benchmark_display_aggregates_only={true|false}]\n"
+      "    [--benchmark_format=<console|json|csv>]\n"
+      "    [--benchmark_out=<filename>]\n"
+      "    [--benchmark_out_format=<json|console|csv>]\n"
+      "    [--benchmark_color={auto|true|false}]\n"
+      "    [--benchmark_counters_tabular={true|false}]\n"
+      "    [--v=<verbosity>]\n");
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_UNDEFINED_OK, &argc, &argv);
   iree_benchmark_initialize(&argc, argv);
-  iree_flags_parse_checked(&argc, &argv);
   iree_benchmark_run_specified();
   return 0;
 }
diff --git a/iree/testing/gtest_main.cc b/iree/testing/gtest_main.cc
index c3d456c..d2c934b 100644
--- a/iree/testing/gtest_main.cc
+++ b/iree/testing/gtest_main.cc
@@ -16,8 +16,9 @@
 #include "iree/testing/gtest.h"
 
 extern "C" int main(int argc, char** argv) {
+  // Pass through flags to gtest.
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_UNDEFINED_OK, &argc, &argv);
   ::testing::InitGoogleTest(&argc, argv);
-  iree_flags_parse_checked(&argc, &argv);
 
   return RUN_ALL_TESTS();
 }
diff --git a/iree/testing/vulkan/CMakeLists.txt b/iree/testing/vulkan/CMakeLists.txt
index f263f0e..3a84ccc 100644
--- a/iree/testing/vulkan/CMakeLists.txt
+++ b/iree/testing/vulkan/CMakeLists.txt
@@ -63,7 +63,6 @@
     "iree-run-module-vulkan-gui-main.cc"
   DEPS
     ::vulkan_gui_util
-    absl::flags
     iree::base::internal::file_io
     iree::base::internal::flags
     iree::base::internal::main
diff --git a/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc b/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc
index 29491ba..1e3f42b 100644
--- a/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc
+++ b/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc
@@ -18,7 +18,6 @@
 #include "iree/testing/vulkan/vulkan_gui_util.h"
 
 // Other dependencies (helpers, etc.)
-#include "absl/flags/flag.h"
 #include "iree/base/internal/file_io.h"
 #include "iree/base/internal/flags.h"
 #include "iree/base/internal/main.h"
@@ -29,29 +28,44 @@
 #include "iree/vm/api.h"
 #include "iree/vm/bytecode_module.h"
 
-ABSL_FLAG(std::string, module_file, "-",
+IREE_FLAG(string, module_file, "-",
           "File containing the module to load that contains the entry "
           "function. Defaults to stdin.");
 
-ABSL_FLAG(std::string, entry_function, "",
+IREE_FLAG(string, entry_function, "",
           "Name of a function contained in the module specified by input_file "
           "to run.");
 
-ABSL_FLAG(std::vector<std::string>, function_inputs, {},
-          "A comma-separated list of of input buffers of the format:"
-          "[shape]xtype=[value]\n"
-          "2x2xi32=1 2 3 4\n"
-          "Optionally, brackets may be used to separate the element values. "
-          "They are ignored by the parser.\n"
-          "2x2xi32=[[1 2][3 4]]\n"
-          "Due to the absence of repeated flags in absl, commas should not be "
-          "used to separate elements. They are reserved for separating input "
-          "values:\n"
-          "2x2xi32=[[1 2][3 4]], 1x2xf32=[[1 2]]");
-
-ABSL_FLAG(std::string, function_inputs_file, "",
-          "Provides a file for input shapes and optional values (see "
-          "ParseToVariantListFromFile in vm_util.h for details)");
+static iree_status_t parse_function_input(iree_string_view_t flag_name,
+                                          void* storage,
+                                          iree_string_view_t value) {
+  auto* list = (std::vector<std::string>*)storage;
+  list->push_back(std::string(value.data, value.size));
+  return iree_ok_status();
+}
+static void print_function_input(iree_string_view_t flag_name, void* storage,
+                                 FILE* file) {
+  auto* list = (std::vector<std::string>*)storage;
+  if (list->empty()) {
+    fprintf(file, "# --%.*s=\n", (int)flag_name.size, flag_name.data);
+  } else {
+    for (size_t i = 0; i < list->size(); ++i) {
+      fprintf(file, "--%.*s=\"%s\"\n", (int)flag_name.size, flag_name.data,
+              list->at(i).c_str());
+    }
+  }
+}
+static std::vector<std::string> FLAG_function_inputs;
+IREE_FLAG_CALLBACK(
+    parse_function_input, print_function_input, &FLAG_function_inputs,
+    function_input,
+    "An input value or buffer of the format:\n"
+    "  [shape]xtype=[value]\n"
+    "  2x2xi32=1 2 3 4\n"
+    "Optionally, brackets may be used to separate the element values:\n"
+    "  2x2xi32=[[1 2][3 4]]\n"
+    "Each occurrence of the flag indicates an input in the order they were\n"
+    "specified on the command line.");
 
 static VkAllocationCallbacks* g_Allocator = NULL;
 static VkInstance g_Instance = VK_NULL_HANDLE;
@@ -89,7 +103,7 @@
 }
 
 Status GetModuleContentsFromFlags(std::string* out_contents) {
-  auto module_file = absl::GetFlag(FLAGS_module_file);
+  auto module_file = std::string(FLAG_module_file);
   if (module_file == "-") {
     *out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
                                 std::istreambuf_iterator<char>()};
@@ -144,7 +158,7 @@
 }  // namespace
 
 extern "C" int iree_main(int argc, char** argv) {
-  iree_flags_parse_checked(&argc, &argv);
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc, &argv);
   IREE_CHECK_OK(iree_hal_vulkan_driver_module_register(
       iree_hal_driver_registry_default()));
 
@@ -322,7 +336,7 @@
   IREE_LOG(INFO) << "Context with modules is ready for use";
 
   // Lookup the entry point function.
-  std::string entry_function = absl::GetFlag(FLAGS_entry_function);
+  std::string entry_function = FLAG_entry_function;
   iree_vm_function_t main_function;
   IREE_CHECK_OK(bytecode_module->lookup_function(
       bytecode_module->self, IREE_VM_FUNCTION_LINKAGE_EXPORT,
@@ -339,25 +353,15 @@
   std::vector<RawSignatureParser::Description> main_function_input_descs;
   IREE_CHECK_OK(ParseInputSignature(main_function, &main_function_input_descs));
   vm::ref<iree_vm_list_t> main_function_inputs;
-  if (!absl::GetFlag(FLAGS_function_inputs_file).empty()) {
-    if (!absl::GetFlag(FLAGS_function_inputs).empty()) {
-      IREE_LOG(FATAL) << "Expected only one of function_inputs and "
-                         "function_inputs_file to be set";
-    }
-    IREE_CHECK_OK(ParseToVariantListFromFile(
-        main_function_input_descs, iree_hal_device_allocator(iree_vk_device),
-        absl::GetFlag(FLAGS_function_inputs_file), &main_function_inputs));
-  } else {
-    IREE_CHECK_OK(ParseToVariantList(
-        main_function_input_descs, iree_hal_device_allocator(iree_vk_device),
-        absl::GetFlag(FLAGS_function_inputs), &main_function_inputs));
-  }
+  IREE_CHECK_OK(ParseToVariantList(
+      main_function_input_descs, iree_hal_device_allocator(iree_vk_device),
+      FLAG_function_inputs, &main_function_inputs));
 
   std::vector<RawSignatureParser::Description> main_function_output_descs;
   IREE_CHECK_OK(
       ParseOutputSignature(main_function, &main_function_output_descs));
 
-  const std::string& window_title = absl::GetFlag(FLAGS_module_file);
+  const std::string window_title = std::string(FLAG_module_file);
   // --------------------------------------------------------------------------
 
   // --------------------------------------------------------------------------
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index c01c6f6..c6592e3 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -39,9 +39,6 @@
         "//iree/tools/utils:vm_util",
         "//iree/vm",
         "//iree/vm:bytecode_module",
-        "@com_google_absl//absl/flags:flag",
-        "@com_google_absl//absl/flags:parse",
-        "@com_google_absl//absl/flags:usage",
         "@com_google_absl//absl/strings",
         "@com_google_benchmark//:benchmark",
     ],
@@ -64,7 +61,6 @@
         "//iree/testing:gtest",
         "//iree/tools/utils:vm_util",
         "//iree/vm:bytecode_module",
-        "@com_google_absl//absl/flags:flag",
         "@com_google_absl//absl/strings",
     ],
 )
@@ -254,7 +250,6 @@
         "//iree/tools/utils:vm_util",
         "//iree/vm",
         "//iree/vm:bytecode_module",
-        "@com_google_absl//absl/flags:flag",
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/types:span",
         "@llvm-project//llvm:Support",
@@ -280,7 +275,6 @@
         "//iree/tools/utils:vm_util",
         "//iree/vm",
         "//iree/vm:bytecode_module",
-        "@com_google_absl//absl/flags:flag",
         "@com_google_absl//absl/strings",
     ],
 )
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index 90c2a90..084989f 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -63,9 +63,6 @@
   SRCS
     "iree-benchmark-module-main.cc"
   DEPS
-    absl::flags
-    absl::flags_parse
-    absl::flags_usage
     absl::strings
     benchmark
     iree::base::internal::file_io
@@ -89,7 +86,6 @@
     "iree-check-module-main.cc"
   DEPS
     iree::modules::check::native_module
-    absl::flags
     absl::strings
     iree::base::api
     iree::base::core_headers
@@ -127,7 +123,6 @@
   SRCS
     "iree-run-module-main.cc"
   DEPS
-    absl::flags
     absl::strings
     iree::base::internal::file_io
     iree::base::internal::flags
@@ -365,7 +360,6 @@
       MLIRPass
       MLIRSupport
       MLIRTargetLLVMIRExport
-      absl::flags
       absl::span
       absl::strings
       iree::base::api
diff --git a/iree/tools/iree-benchmark-module-main.cc b/iree/tools/iree-benchmark-module-main.cc
index a225339..d2e318b 100644
--- a/iree/tools/iree-benchmark-module-main.cc
+++ b/iree/tools/iree-benchmark-module-main.cc
@@ -12,10 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "absl/flags/flag.h"
-#include "absl/flags/internal/parse.h"
-#include "absl/flags/usage.h"
-#include "absl/strings/string_view.h"
 #include "benchmark/benchmark.h"
 #include "iree/base/internal/file_io.h"
 #include "iree/base/internal/flags.h"
@@ -27,39 +23,54 @@
 #include "iree/vm/api.h"
 #include "iree/vm/bytecode_module.h"
 
-ABSL_FLAG(std::string, module_file, "-",
+IREE_FLAG(string, module_file, "-",
           "File containing the module to load that contains the entry "
           "function. Defaults to stdin.");
 
 // TODO(hanchung): Extract the batch size using
 // iree_vm_function_reflection_attr.
-ABSL_FLAG(
-    int, batch_size, 1,
+IREE_FLAG(
+    int32_t, batch_size, 1,
     "The number of batch size, which is expected to match "
     "iree-hal-benchmark-dispatch-repeat-count when translating the module");
 
-ABSL_FLAG(std::string, entry_function, "",
+IREE_FLAG(string, entry_function, "",
           "Name of a function contained in the module specified by module_file "
           "to run. If this is not set, all the exported functions will be "
           "benchmarked and they are expected to not have input arguments.");
 
-ABSL_FLAG(std::string, driver, "vmla", "Backend driver to use.");
+IREE_FLAG(string, driver, "vmla", "Backend driver to use.");
 
-ABSL_FLAG(std::vector<std::string>, function_inputs, {},
-          "A comma-separated list of of input buffers of the format:"
-          "[shape]xtype=[value]\n"
-          "2x2xi32=1 2 3 4\n"
-          "Optionally, brackets may be used to separate the element values. "
-          "They are ignored by the parser.\n"
-          "2x2xi32=[[1 2][3 4]]\n"
-          "Due to the absence of repeated flags in absl, commas should not be "
-          "used to separate elements. They are reserved for separating input "
-          "values:\n"
-          "2x2xi32=[[1 2][3 4]], 1x2xf32=[[1 2]]");
-
-ABSL_FLAG(std::string, function_inputs_file, "",
-          "Provides a file for input shapes and optional values (see "
-          "ParseToVariantListFromFile in vm_util.h for details)");
+static iree_status_t parse_function_input(iree_string_view_t flag_name,
+                                          void* storage,
+                                          iree_string_view_t value) {
+  auto* list = (std::vector<std::string>*)storage;
+  list->push_back(std::string(value.data, value.size));
+  return iree_ok_status();
+}
+static void print_function_input(iree_string_view_t flag_name, void* storage,
+                                 FILE* file) {
+  auto* list = (std::vector<std::string>*)storage;
+  if (list->empty()) {
+    fprintf(file, "# --%.*s=\n", (int)flag_name.size, flag_name.data);
+  } else {
+    for (size_t i = 0; i < list->size(); ++i) {
+      fprintf(file, "--%.*s=\"%s\"\n", (int)flag_name.size, flag_name.data,
+              list->at(i).c_str());
+    }
+  }
+}
+static std::vector<std::string> FLAG_function_inputs;
+IREE_FLAG_CALLBACK(
+    parse_function_input, print_function_input, &FLAG_function_inputs,
+    function_input,
+    "An input value or buffer of the format:\n"
+    "  [shape]xtype=[value]\n"
+    "  2x2xi32=1 2 3 4\n"
+    "Optionally, brackets may be used to separate the element values:\n"
+    "  2x2xi32=[[1 2][3 4]]\n"
+    "Each occurrence of the flag indicates an input in the order they were\n"
+    "specified on the command line.");
 
 namespace iree {
 namespace {
@@ -91,7 +102,7 @@
     iree_vm_function_t function, iree_vm_list_t* inputs,
     const std::vector<RawSignatureParser::Description>& output_descs) {
   auto benchmark_name = "BM_" + function_name;
-  int batch_size = absl::GetFlag(FLAGS_batch_size);
+  int batch_size = FLAG_batch_size;
   benchmark::RegisterBenchmark(
       benchmark_name.c_str(),
       [benchmark_name, batch_size, context, function, inputs,
@@ -116,7 +127,7 @@
 
 Status GetModuleContentsFromFlags(std::string* out_contents) {
   IREE_TRACE_SCOPE0("GetModuleContentsFromFlags");
-  auto module_file = absl::GetFlag(FLAGS_module_file);
+  auto module_file = std::string(FLAG_module_file);
   if (module_file == "-") {
     *out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
                                 std::istreambuf_iterator<char>()};
@@ -156,7 +167,7 @@
       IREE_RETURN_IF_ERROR(Init());
     }
 
-    auto function_name = absl::GetFlag(FLAGS_entry_function);
+    auto function_name = std::string(FLAG_entry_function);
     if (!function_name.empty()) {
       IREE_RETURN_IF_ERROR(RegisterSpecificFunction(function_name));
     } else {
@@ -178,7 +189,7 @@
 
     // Create IREE's device and module.
     IREE_RETURN_IF_ERROR(
-        iree::CreateDevice(absl::GetFlag(FLAGS_driver), &device_));
+        iree::CreateDevice(std::string(FLAG_driver), &device_));
     IREE_RETURN_IF_ERROR(CreateHalModule(device_, &hal_module_));
     IREE_RETURN_IF_ERROR(LoadBytecodeModule(module_data_, &input_module_));
 
@@ -206,15 +217,9 @@
     // Construct inputs.
     std::vector<RawSignatureParser::Description> input_descs;
     IREE_RETURN_IF_ERROR(ParseInputSignature(function, &input_descs));
-    if (!absl::GetFlag(FLAGS_function_inputs_file).empty()) {
-      IREE_RETURN_IF_ERROR(ParseToVariantListFromFile(
-          input_descs, iree_hal_device_allocator(device_),
-          absl::GetFlag(FLAGS_function_inputs_file), &inputs_));
-    } else {
-      IREE_RETURN_IF_ERROR(
-          ParseToVariantList(input_descs, iree_hal_device_allocator(device_),
-                             absl::GetFlag(FLAGS_function_inputs), &inputs_));
-    }
+    IREE_CHECK_OK(ParseToVariantList(input_descs,
+                                     iree_hal_device_allocator(device_),
+                                     FLAG_function_inputs, &inputs_));
 
     // Creates output signature.
     std::vector<RawSignatureParser::Description> output_descs;
@@ -266,25 +271,12 @@
 int main(int argc, char** argv) {
   IREE_TRACE_SCOPE0("main");
 
-  // We have to contend with two flag parsing libraries here: absl's and
-  // benchmark's. To make matters worse, both define the `--help` flag. To
-  // ensure that each is able to parse its own flags, we use an absl "internal"
-  // function (still with public visibility) to parse while ignoring undefined
-  // flags. If it sees `--help` it will exit here, so we include the benchmark
-  // library usage information in the manually-set help output. Then we let
-  // benchmark parse its flags. Finally we call the normal initialization
-  // function to do other IREE initialization including flag parsing with
-  // normal options. Any remaining flags will be unknown and result in an error.
-  absl::SetProgramUsageMessage(
-      "iree-benchmark-module \n"
-      "    --module_file=module.vmfb\n"
-      "    --entry_function=exported_function_to_benchmark\n"
-      "      If this is not set, all the exported functions will be \n"
-      "      benchmarked and they are expected to not have input arguments\n"
-      "    [--function_inputs=2xi32=1 2,1x2xf32=2 1 | \n"
-      "     --function_inputs_file=file_with_function_inputs]\n"
-      "    [--driver=vmla]\n"
-      "\n\n"
+  // We have to contend with two flag parsing libraries here: IREE's and
+  // benchmark's. We let flags go to IREE first and then it'll pass any it
+  // doesn't recognize on to benchmark. We let IREE handle the help, though, so
+  // we need to include the relevant benchmark flags for users.
+  iree_flags_set_usage(
+      "iree-benchmark-module",
       "  Optional flags from third_party/benchmark/src/benchmark.cc:\n"
       "    [--benchmark_list_tests={true|false}]\n"
       "    [--benchmark_filter=<regex>]\n"
@@ -298,12 +290,8 @@
       "    [--benchmark_color={auto|true|false}]\n"
       "    [--benchmark_counters_tabular={true|false}]\n"
       "    [--v=<verbosity>]\n");
-  absl::flags_internal::ParseCommandLineImpl(
-      argc, argv, absl::flags_internal::ArgvListAction::kRemoveParsedArgs,
-      absl::flags_internal::UsageFlagsAction::kHandleUsage,
-      absl::flags_internal::OnUndefinedFlag::kIgnoreUndefined);
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_UNDEFINED_OK, &argc, &argv);
   ::benchmark::Initialize(&argc, argv);
-  iree_flags_parse_checked(&argc, &argv);
   IREE_CHECK_OK(iree_hal_register_all_available_drivers(
       iree_hal_driver_registry_default()));
 
diff --git a/iree/tools/iree-check-module-main.cc b/iree/tools/iree-check-module-main.cc
index fe0e00e..caa9578 100644
--- a/iree/tools/iree-check-module-main.cc
+++ b/iree/tools/iree-check-module-main.cc
@@ -14,7 +14,6 @@
 
 #include <iostream>
 
-#include "absl/flags/flag.h"
 #include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 #include "iree/base/api.h"
@@ -41,9 +40,9 @@
 #define IREE_FORCE_BINARY_STDIN()
 #endif  // IREE_PLATFORM_WINDOWS
 
-ABSL_FLAG(std::string, driver, "vmla", "Backend driver to use.");
+IREE_FLAG(string, driver, "vmla", "Backend driver to use.");
 
-ABSL_FLAG(
+IREE_FLAG(
     bool, expect_failure, false,
     "Whether running module is expected to fail. If set, failing "
     "statuses from function evaluation are logged and ignored and all "
@@ -104,7 +103,7 @@
   IREE_RETURN_IF_ERROR(LoadBytecodeModule(module_data, &input_module));
 
   iree_hal_device_t* device = nullptr;
-  IREE_RETURN_IF_ERROR(CreateDevice(absl::GetFlag(FLAGS_driver), &device));
+  IREE_RETURN_IF_ERROR(CreateDevice(std::string(FLAG_driver), &device));
   iree_vm_module_t* hal_module = nullptr;
   IREE_RETURN_IF_ERROR(CreateHalModule(device, &hal_module));
   iree_vm_module_t* check_module = nullptr;
@@ -179,7 +178,7 @@
 }  // namespace
 
 extern "C" int main(int argc, char** argv) {
-  iree_flags_parse_checked(&argc, &argv);
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_UNDEFINED_OK, &argc, &argv);
   IREE_CHECK_OK(iree_hal_register_all_available_drivers(
       iree_hal_driver_registry_default()));
   ::testing::InitGoogleTest(&argc, argv);
@@ -195,7 +194,7 @@
   int exit_code = 1;
   auto status = Run(std::move(module_file_path), &exit_code);
   int ret = status.ok() ? exit_code : 1;
-  if (absl::GetFlag(FLAGS_expect_failure)) {
+  if (FLAG_expect_failure) {
     if (ret == 0) {
       std::cout << "Test passed but expected failure\n";
       std::cout << status;
diff --git a/iree/tools/iree-run-mlir-main.cc b/iree/tools/iree-run-mlir-main.cc
index 099b91c..8746c9a 100644
--- a/iree/tools/iree-run-mlir-main.cc
+++ b/iree/tools/iree-run-mlir-main.cc
@@ -39,7 +39,6 @@
 #include <iostream>
 #include <utility>
 
-#include "absl/flags/flag.h"
 #include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/span.h"
@@ -120,13 +119,6 @@
     llvm::cl::ZeroOrMore,
 };
 
-static llvm::cl::opt<std::string> function_inputs_file_flag{
-    "function-input-file",
-    llvm::cl::desc("Provides a file for input shapes and optional values (see "
-                   "ParseToVariantListFromFile in vm_util.h for details)"),
-    llvm::cl::init(""),
-};
-
 static llvm::cl::opt<bool> run_flag{
     "run",
     llvm::cl::desc("Runs the module (vs. just compiling and verifing)"),
@@ -274,21 +266,11 @@
   std::vector<RawSignatureParser::Description> input_descs;
   IREE_RETURN_IF_ERROR(ParseInputSignature(function, &input_descs));
   vm::ref<iree_vm_list_t> inputs;
-  if (!function_inputs_file_flag.empty()) {
-    if (!function_inputs_flag.empty()) {
-      return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
-                              "expected only one of function_inputs and "
-                              "function_inputs_file to be set");
-    }
-    IREE_RETURN_IF_ERROR(ParseToVariantListFromFile(
-        input_descs, allocator, function_inputs_file_flag, &inputs));
-  } else {
-    auto function_inputs_list = absl::MakeConstSpan(
-        function_inputs_flag.empty() ? nullptr : &function_inputs_flag.front(),
-        function_inputs_flag.size());
-    IREE_RETURN_IF_ERROR(ParseToVariantList(input_descs, allocator,
-                                            function_inputs_list, &inputs));
-  }
+  auto function_inputs_list = absl::MakeConstSpan(
+      function_inputs_flag.empty() ? nullptr : &function_inputs_flag.front(),
+      function_inputs_flag.size());
+  IREE_RETURN_IF_ERROR(ParseToVariantList(input_descs, allocator,
+                                          function_inputs_list, &inputs));
 
   std::vector<RawSignatureParser::Description> output_descs;
   IREE_RETURN_IF_ERROR(ParseOutputSignature(function, &output_descs));
@@ -520,7 +502,8 @@
   }
   argc_absl += run_args_flag.size();
   char** argv_absl_ptr = argv_absl.data();
-  iree_flags_parse_checked(&argc_absl, &argv_absl_ptr);
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc_absl,
+                           &argv_absl_ptr);
   IREE_CHECK_OK(iree_hal_register_all_available_drivers(
       iree_hal_driver_registry_default()));
 
diff --git a/iree/tools/iree-run-module-main.cc b/iree/tools/iree-run-module-main.cc
index d4015a3..24d4934 100644
--- a/iree/tools/iree-run-module-main.cc
+++ b/iree/tools/iree-run-module-main.cc
@@ -14,7 +14,6 @@
 
 #include <iostream>
 
-#include "absl/flags/flag.h"
 #include "absl/strings/string_view.h"
 #include "iree/base/internal/file_io.h"
 #include "iree/base/internal/flags.h"
@@ -26,38 +25,53 @@
 #include "iree/vm/api.h"
 #include "iree/vm/bytecode_module.h"
 
-ABSL_FLAG(std::string, module_file, "-",
+IREE_FLAG(string, module_file, "-",
           "File containing the module to load that contains the entry "
           "function. Defaults to stdin.");
 
-ABSL_FLAG(std::string, entry_function, "",
+IREE_FLAG(string, entry_function, "",
           "Name of a function contained in the module specified by module_file "
           "to run.");
 
-ABSL_FLAG(std::string, driver, "vmla", "Backend driver to use.");
+IREE_FLAG(string, driver, "vmla", "Backend driver to use.");
 
-ABSL_FLAG(std::vector<std::string>, function_inputs, {},
-          "A comma-separated list of of input buffers of the format:"
-          "[shape]xtype=[value]\n"
-          "2x2xi32=1 2 3 4\n"
-          "Optionally, brackets may be used to separate the element values. "
-          "They are ignored by the parser.\n"
-          "2x2xi32=[[1 2][3 4]]\n"
-          "Due to the absence of repeated flags in absl, commas should not be "
-          "used to separate elements. They are reserved for separating input "
-          "values:\n"
-          "2x2xi32=[[1 2][3 4]], 1x2xf32=[[1 2]]");
-
-ABSL_FLAG(std::string, function_inputs_file, "",
-          "Provides a file for input shapes and optional values (see "
-          "ParseToVariantListFromFile in vm_util.h for details)");
+static iree_status_t parse_function_input(iree_string_view_t flag_name,
+                                          void* storage,
+                                          iree_string_view_t value) {
+  auto* list = (std::vector<std::string>*)storage;
+  list->push_back(std::string(value.data, value.size));
+  return iree_ok_status();
+}
+static void print_function_input(iree_string_view_t flag_name, void* storage,
+                                 FILE* file) {
+  auto* list = (std::vector<std::string>*)storage;
+  if (list->empty()) {
+    fprintf(file, "# --%.*s=\n", (int)flag_name.size, flag_name.data);
+  } else {
+    for (size_t i = 0; i < list->size(); ++i) {
+      fprintf(file, "--%.*s=\"%s\"\n", (int)flag_name.size, flag_name.data,
+              list->at(i).c_str());
+    }
+  }
+}
+static std::vector<std::string> FLAG_function_inputs;
+IREE_FLAG_CALLBACK(
+    parse_function_input, print_function_input, &FLAG_function_inputs,
+    function_input,
+    "An input value or buffer of the format:\n"
+    "  [shape]xtype=[value]\n"
+    "  2x2xi32=1 2 3 4\n"
+    "Optionally, brackets may be used to separate the element values:\n"
+    "  2x2xi32=[[1 2][3 4]]\n"
+    "Each occurrence of the flag indicates an input in the order they were\n"
+    "specified on the command line.");
 
 namespace iree {
 namespace {
 
 Status GetModuleContentsFromFlags(std::string* out_contents) {
   IREE_TRACE_SCOPE0("GetModuleContentsFromFlags");
-  auto module_file = absl::GetFlag(FLAGS_module_file);
+  auto module_file = std::string(FLAG_module_file);
   if (module_file == "-") {
     *out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
                                 std::istreambuf_iterator<char>()};
@@ -84,7 +98,7 @@
   IREE_RETURN_IF_ERROR(LoadBytecodeModule(module_data, &input_module));
 
   iree_hal_device_t* device = nullptr;
-  IREE_RETURN_IF_ERROR(CreateDevice(absl::GetFlag(FLAGS_driver), &device));
+  IREE_RETURN_IF_ERROR(CreateDevice(std::string(FLAG_driver), &device));
   iree_vm_module_t* hal_module = nullptr;
   IREE_RETURN_IF_ERROR(CreateHalModule(device, &hal_module));
 
@@ -96,7 +110,7 @@
                            iree_allocator_system(), &context),
                        "creating context");
 
-  std::string function_name = absl::GetFlag(FLAGS_entry_function);
+  std::string function_name = std::string(FLAG_entry_function);
   iree_vm_function_t function;
   if (function_name.empty()) {
     return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
@@ -115,20 +129,9 @@
   IREE_RETURN_IF_ERROR(ParseInputSignature(function, &input_descs));
 
   vm::ref<iree_vm_list_t> inputs;
-  if (!absl::GetFlag(FLAGS_function_inputs_file).empty()) {
-    if (!absl::GetFlag(FLAGS_function_inputs).empty()) {
-      return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
-                              "expected only one of function_inputs and "
-                              "function_inputs_file to be set");
-    }
-    IREE_RETURN_IF_ERROR(ParseToVariantListFromFile(
-        input_descs, iree_hal_device_allocator(device),
-        absl::GetFlag(FLAGS_function_inputs_file), &inputs));
-  } else {
-    IREE_RETURN_IF_ERROR(ParseToVariantList(
-        input_descs, iree_hal_device_allocator(device),
-        absl::MakeConstSpan(absl::GetFlag(FLAGS_function_inputs)), &inputs));
-  }
+  IREE_CHECK_OK(ParseToVariantList(input_descs,
+                                   iree_hal_device_allocator(device),
+                                   FLAG_function_inputs, &inputs));
 
   std::vector<RawSignatureParser::Description> output_descs;
   IREE_RETURN_IF_ERROR(ParseOutputSignature(function, &output_descs));
@@ -159,7 +162,7 @@
 }  // namespace
 
 extern "C" int main(int argc, char** argv) {
-  iree_flags_parse_checked(&argc, &argv);
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc, &argv);
   IREE_CHECK_OK(iree_hal_register_all_available_drivers(
       iree_hal_driver_registry_default()));
   IREE_CHECK_OK(Run());
diff --git a/iree/tools/test/benchmark_flags.txt b/iree/tools/test/benchmark_flags.txt
index c1ce1fc..2c3a8c1 100644
--- a/iree/tools/test/benchmark_flags.txt
+++ b/iree/tools/test/benchmark_flags.txt
@@ -1,22 +1,16 @@
-// HELP: iree-benchmark-module
-// HELP: --module_file
-// HELP: --benchmark_list_tests
 // RUN: ( iree-benchmark-module --help || [[ $? == 1 ]] )  | IreeFileCheck --check-prefix=HELP %s
-// RUN: ( iree-benchmark-module --helpshort || [[ $? == 1 ]] ) | IreeFileCheck --check-prefix=HELP %s
+// HELP: --benchmark_list_tests
+// HELP: --module_file
 
-// UNKNOWN: unknown-flag
-// RUN: ( iree-benchmark-module --unknown-flag 2>&1 || [[ $? == 1 ]] ) | IreeFileCheck --check-prefix=UNKNOWN %s
-// RUN: ( iree-benchmark-module --driver=vmla --unknown-flag --benchmark_list_tests 2>&1 || [[ $? == 1 ]] ) | IreeFileCheck --check-prefix=UNKNOWN %s
-
-// LIST-BENCHMARKS: BM_foo1
-// LIST-BENCHMARKS: BM_foo2
 // RUN: ( iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --benchmark_list_tests --driver=vmla --benchmark_list_tests ) | IreeFileCheck --check-prefix=LIST-BENCHMARKS %s
 module {
+  // LIST-BENCHMARKS: BM_foo1
   func @foo1() -> tensor<4xf32> attributes { iree.module.export } {
     %input = iree.unfoldable_constant dense<[0.0, 1.0, 2.0, 4.0]> : tensor<4xf32>
     %result = "mhlo.exponential"(%input) : (tensor<4xf32>) -> tensor<4xf32>
     return %result : tensor<4xf32>
   }
+  // LIST-BENCHMARKS: BM_foo2
   func @foo2() -> tensor<4xf32> attributes { iree.module.export } {
     %input = iree.unfoldable_constant dense<[0.0, 1.0, 2.0, 4.0]> : tensor<4xf32>
     %result = "mhlo.abs"(%input) : (tensor<4xf32>) -> tensor<4xf32>
diff --git a/iree/tools/test/iree-benchmark-module.mlir b/iree/tools/test/iree-benchmark-module.mlir
index a75b639..c4a4e32 100644
--- a/iree/tools/test/iree-benchmark-module.mlir
+++ b/iree/tools/test/iree-benchmark-module.mlir
@@ -1,6 +1,6 @@
-// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vmla --entry_function=abs --function_inputs="i32=-2" | IreeFileCheck %s
-// RUN: [[ $IREE_VULKAN_DISABLE == 1 ]] || (iree-translate --iree-hal-target-backends=vulkan-spirv -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vulkan --entry_function=abs --function_inputs="i32=-2" | IreeFileCheck %s)
-// RUN: [[ $IREE_LLVMAOT_DISABLE == 1 ]] || (iree-translate --iree-hal-target-backends=dylib-llvm-aot -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=dylib --entry_function=abs --function_inputs="i32=-2" | IreeFileCheck %s)
+// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vmla --entry_function=abs --function_input=i32=-2 | IreeFileCheck %s
+// RUN: [[ $IREE_VULKAN_DISABLE == 1 ]] || (iree-translate --iree-hal-target-backends=vulkan-spirv -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vulkan --entry_function=abs --function_input=i32=-2 | IreeFileCheck %s)
+// RUN: [[ $IREE_LLVMAOT_DISABLE == 1 ]] || (iree-translate --iree-hal-target-backends=dylib-llvm-aot -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=dylib --entry_function=abs --function_input=i32=-2 | IreeFileCheck %s)
 
 // CHECK-LABEL: BM_abs
 func @abs(%input : tensor<i32>) -> (tensor<i32>) attributes { iree.module.export } {
diff --git a/iree/tools/test/iree-run-module.mlir b/iree/tools/test/iree-run-module.mlir
index a97daf9..763195a 100644
--- a/iree/tools/test/iree-run-module.mlir
+++ b/iree/tools/test/iree-run-module.mlir
@@ -1,6 +1,6 @@
-// RUN: (iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-run-module --driver=vmla --entry_function=abs --function_inputs="i32=-2") | IreeFileCheck %s
-// RUN: [[ $IREE_VULKAN_DISABLE == 1 ]] || ((iree-translate --iree-hal-target-backends=vulkan-spirv -iree-mlir-to-vm-bytecode-module %s | iree-run-module --driver=vulkan --entry_function=abs --function_inputs="i32=-2") | IreeFileCheck %s)
-// RUN: [[ $IREE_LLVMAOT_DISABLE == 1 ]] || ((iree-translate --iree-hal-target-backends=dylib-llvm-aot -iree-mlir-to-vm-bytecode-module %s | iree-run-module --driver=dylib --entry_function=abs --function_inputs="i32=-2") | IreeFileCheck %s)
+// RUN: (iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-run-module --driver=vmla --entry_function=abs --function_input=i32=-2) | IreeFileCheck %s
+// RUN: [[ $IREE_VULKAN_DISABLE == 1 ]] || ((iree-translate --iree-hal-target-backends=vulkan-spirv -iree-mlir-to-vm-bytecode-module %s | iree-run-module --driver=vulkan --entry_function=abs --function_input=i32=-2) | IreeFileCheck %s)
+// RUN: [[ $IREE_LLVMAOT_DISABLE == 1 ]] || ((iree-translate --iree-hal-target-backends=dylib-llvm-aot -iree-mlir-to-vm-bytecode-module %s | iree-run-module --driver=dylib --entry_function=abs --function_input=i32=-2) | IreeFileCheck %s)
 
 // CHECK-LABEL: EXEC @abs
 func @abs(%input : tensor<i32>) -> (tensor<i32>) attributes { iree.module.export } {
diff --git a/iree/tools/test/multiple_args.mlir b/iree/tools/test/multiple_args.mlir
index f28afa7..cb725ce 100644
--- a/iree/tools/test/multiple_args.mlir
+++ b/iree/tools/test/multiple_args.mlir
@@ -1,6 +1,6 @@
-// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-run-module --entry_function=multi_input --function_inputs='2xi32=[1 2], 2xi32=[3 4]' | IreeFileCheck %s
+// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-run-module --entry_function=multi_input --function_input="2xi32=[1 2]" --function_input="2xi32=[3 4]" | IreeFileCheck %s
 // RUN: iree-run-mlir --iree-hal-target-backends=vmla --function-input='2xi32=[1 2]' --function-input='2xi32=[3 4]' %s | IreeFileCheck %s
-// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vmla --entry_function=multi_input --function_inputs='2xi32=[1 2], 2xi32=[3 4]' | IreeFileCheck --check-prefix=BENCHMARK %s
+// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vmla --entry_function=multi_input --function_input="2xi32=[1 2]" --function_input="2xi32=[3 4]" | IreeFileCheck --check-prefix=BENCHMARK %s
 
 // BENCHMARK-LABEL: BM_multi_input
 // CHECK-LABEL: EXEC @multi_input
diff --git a/iree/tools/test/scalars.mlir b/iree/tools/test/scalars.mlir
index daf1872..d6a5546 100644
--- a/iree/tools/test/scalars.mlir
+++ b/iree/tools/test/scalars.mlir
@@ -1,5 +1,5 @@
-// RUN: (iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-run-module --entry_function=scalar --function_inputs='i32=42') | IreeFileCheck %s
-// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vmla --entry_function=scalar --function_inputs='i32=42' | IreeFileCheck --check-prefix=BENCHMARK %s
+// RUN: (iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-run-module --entry_function=scalar --function_input=i32=42) | IreeFileCheck %s
+// RUN: iree-translate --iree-hal-target-backends=vmla -iree-mlir-to-vm-bytecode-module %s | iree-benchmark-module --driver=vmla --entry_function=scalar --function_input=i32=42 | IreeFileCheck --check-prefix=BENCHMARK %s
 // RUN: (iree-run-mlir --iree-hal-target-backends=vmla --function-input=i32=42 %s) | IreeFileCheck %s
 
 // BENCHMARK-LABEL: BM_scalar
diff --git a/iree/tools/utils/vm_util.cc b/iree/tools/utils/vm_util.cc
index 27f0cd2..3b3e06d 100644
--- a/iree/tools/utils/vm_util.cc
+++ b/iree/tools/utils/vm_util.cc
@@ -177,17 +177,6 @@
   return ParseToVariantList(descs, allocator, input_views, out_list);
 }
 
-Status ParseToVariantListFromFile(
-    absl::Span<const RawSignatureParser::Description> descs,
-    iree_hal_allocator_t* allocator, const std::string& filename,
-    iree_vm_list_t** out_list) {
-  std::string contents;
-  IREE_RETURN_IF_ERROR(file_io::GetFileContents(filename.c_str(), &contents));
-  std::vector<absl::string_view> input_views(
-      absl::StrSplit(contents, '\n', absl::SkipEmpty()));
-  return ParseToVariantList(descs, allocator, input_views, out_list);
-}
-
 Status PrintVariantList(absl::Span<const RawSignatureParser::Description> descs,
                         iree_vm_list_t* variant_list, std::ostream* os) {
   for (int i = 0; i < iree_vm_list_size(variant_list); ++i) {
diff --git a/iree/tools/utils/vm_util.h b/iree/tools/utils/vm_util.h
index 19cf92a..006961a 100644
--- a/iree/tools/utils/vm_util.h
+++ b/iree/tools/utils/vm_util.h
@@ -62,14 +62,6 @@
     iree_hal_allocator_t* allocator,
     absl::Span<const std::string> input_strings, iree_vm_list_t** out_list);
 
-// Parses the content in |filename| into a variant list of VM scalars and
-// buffers. See ParseToVariantList for the format of scalars and buffers. The
-// inputs are expected to be newline-separated.
-Status ParseToVariantListFromFile(
-    absl::Span<const RawSignatureParser::Description> descs,
-    iree_hal_allocator_t* allocator, const std::string& filename,
-    iree_vm_list_t** out_list);
-
 // Prints a variant list of VM scalars and buffers to |os|.
 // Prints scalars in the format:
 //   type=value