Add --iree-opt-numeric-precision-reduction option. (#8010)

* Prefixes other high level optimization options with "--iree-opt".
* Adds optimization-options.md and backfills with existing options.
* Wire up numeric precision reduction passes.
diff --git a/docs/website/docs/reference/optimization-options.md b/docs/website/docs/reference/optimization-options.md
new file mode 100644
index 0000000..b980938
--- /dev/null
+++ b/docs/website/docs/reference/optimization-options.md
@@ -0,0 +1,54 @@
+# Optimization Options
+
+This page documents various supported flags for optimizing IREE programs. Each
+is presented with its English name, flag to enable/disable, and default state.
+
+These flags can be passed to the:
+
+* `ireec` command line tool
+* `extra_args=["--flag"]` argument to `iree.compiler.tools` Python wrappers
+* In-process Python compiler API
+  `iree.compiler.transforms.ireec.CompilerOptions("--flag", "--flag2")`
+  constructor
+* `ireeCompilerOptionsSetFlags()` compiler C API function
+
+## High level program optimizations
+
+### Constant evaluation (`--iree-opt-const-eval` (off))
+
+Performs compile-time evaluation of any global initializers which produce
+the initial values for global constants, storing the global directly in the
+program as constant data. This extracts such constant program fragments and
+recursively compiles them, using the runtime to evaluate the results.
+
+Note that this only has any effect on computations in module initializer
+functions, not free-standing operations in the program which may produce
+constant-derived results. See `--iree-opt-const-expr-hoisting` for options to
+optimize these.
+
+### Constant expression hoisting (`--iree-opt-const-expr-hoisting` (off))
+
+Identifies all trees of constant expressions in the program and uses a
+heuristic to determine which would be profitable to hoist into global
+initializers for evaluation at module load. Together with
+`--iree-opt-const-eval`, this will convert eligible trees of expressions to
+purely static data embedded in the module.
+
+The heuristic is currently relatively primitive, using static information to
+disable hoisting of leaf operations which are metadata only (i.e.
+broadcasts, etc) or are expected to fold away as part of operator fusion.
+Notably, the current heuristic is likely to pessimize module size in the case of
+complicated programs with trees of constant, large tensors.
+
+### Numeric precision reduction (`--iree-opt-numeric-precision-reduction` (off))
+
+Analyzes program constant data and program flow to identify math operations
+which can be safely evaluated with reduced precision (currently with a minimum
+of 8bit integers but being extended to infer any bit depth) and inserts
+appropriate casts. In conjunction with *Constant Expression Hoisting*,
+*Constant Evaluation* and other automatic optimizations, this can produce
+programs where large amounts (up to the whole) have had their numeric operations
+and constant data rewritten to lower precision types.
+
+This feature is actively evolving and will be the subject of dedicated
+documentation when ready.
diff --git a/docs/website/mkdocs.yml b/docs/website/mkdocs.yml
index 1178135..a75eead 100644
--- a/docs/website/mkdocs.yml
+++ b/docs/website/mkdocs.yml
@@ -117,6 +117,8 @@
       - TensorFlow Lite: 'bindings/tensorflow-lite.md'
   - 'Extensions':
       - 'extensions/index.md'
+  - 'Reference':
+      - Optimization Options: 'reference/optimization-options.md'
   - 'Community':
       - 'community/index.md'
   - 'Blog':
diff --git a/iree/compiler/Dialect/Flow/Transforms/Passes.cpp b/iree/compiler/Dialect/Flow/Transforms/Passes.cpp
index f1a7f30..805ce79 100644
--- a/iree/compiler/Dialect/Flow/Transforms/Passes.cpp
+++ b/iree/compiler/Dialect/Flow/Transforms/Passes.cpp
@@ -95,6 +95,12 @@
     transformOptions.buildConstEvalPassPipeline(pipeline);
   }
 
+  if (transformOptions.numericPrecisionReduction) {
+    pipeline.addPass(createInferNumericNarrowingPass());
+    pipeline.addPass(createOptimizeNumericsPass());
+    pipeline.addPass(createCleanupNumericNarrowingPass());
+  }
+
   FunctionLikeNest(pipeline)
       .addPass(mlir::createCanonicalizerPass)
       .addPass(mlir::createCSEPass);
diff --git a/iree/compiler/Dialect/Flow/Transforms/Passes.h b/iree/compiler/Dialect/Flow/Transforms/Passes.h
index fb9854a..103d428 100644
--- a/iree/compiler/Dialect/Flow/Transforms/Passes.h
+++ b/iree/compiler/Dialect/Flow/Transforms/Passes.h
@@ -30,6 +30,9 @@
   // become the default.
   bool constExprHoisting = false;
 
+  // Enables passes to perform numeric precision reduction.
+  bool numericPrecisionReduction = false;
+
   // Hook to populate a constant evaluation pass pipeline. If nullptr, then
   // no passes are added for constant evaluation. This must be injected in
   // because constant-evaluators can depend on the whole compiler, of which
diff --git a/iree/compiler/Translation/IREEVM.cpp b/iree/compiler/Translation/IREEVM.cpp
index a9eeb7f..5f16a90 100644
--- a/iree/compiler/Translation/IREEVM.cpp
+++ b/iree/compiler/Translation/IREEVM.cpp
@@ -69,16 +69,21 @@
       "IREE options for controlling high level optimizations");
 
   binder.opt<bool>(
-      "iree-const-eval", constEval,
+      "iree-opt-const-eval", constEval,
       llvm::cl::desc("Enables eager evaluation of constants using the full "
                      "compiler and runtime"),
       llvm::cl::cat(category));
   binder.opt<bool>(
-      "iree-const-expr-hoisting", constExprHoisting,
+      "iree-opt-const-expr-hoisting", constExprHoisting,
       llvm::cl::desc(
           "Hoists the results of latent constant expressions into immutable "
           "global initializers for evaluation at program load"),
       llvm::cl::cat(category));
+  binder.opt<bool>(
+      "iree-opt-numeric-precision-reduction", numericPrecisionReduction,
+      llvm::cl::desc(
+          "Reduces numeric precision to lower bit depths where possible"),
+      llvm::cl::cat(category));
 }
 
 void buildIREEVMTransformPassPipeline(
@@ -122,6 +127,8 @@
       passManager.addPass(ConstEval::createJitGlobalsPass());
     };
   }
+  flowOptions.numericPrecisionReduction =
+      highLevelOptimizationOptions.numericPrecisionReduction;
 
   IREE::Flow::buildFlowTransformPassPipeline(passManager, flowOptions);
   IREE::Stream::TransformOptions streamOptions;
diff --git a/iree/compiler/Translation/IREEVM.h b/iree/compiler/Translation/IREEVM.h
index dbf601f..550b454 100644
--- a/iree/compiler/Translation/IREEVM.h
+++ b/iree/compiler/Translation/IREEVM.h
@@ -72,6 +72,9 @@
   // and runtime.
   bool constEval = false;
 
+  // Optimizations to reduce numeric precision where it is safe to do so.
+  bool numericPrecisionReduction = false;
+
   void bindOptions(OptionsBinder &binder);
   using FromFlags = OptionsFromFlags<HighLevelOptimizationOptions>;
 };