Use help-text generator for dex2oat

The use of a static text blob makes keeping the dex2oat help text up
to date difficult. Change to use the new cmdline help-text generator
code.

Test: dex2oat --help
Change-Id: I1139cba2c773242e15f863d7efd2c7050c05ab4f
diff --git a/cmdline/cmdline_parser.h b/cmdline/cmdline_parser.h
index 86e3b2c..22eb44c 100644
--- a/cmdline/cmdline_parser.h
+++ b/cmdline/cmdline_parser.h
@@ -755,10 +755,12 @@
       vios.Stream();
     }
   }
-  vios.Stream() << "The following arguments are ignored for compatibility:" << std::endl;
-  ScopedIndentation si(&vios);
-  for (auto ign : ignore_list_) {
-    vios.Stream() << ign << std::endl;
+  if (!ignore_list_.empty()) {
+    vios.Stream() << "The following arguments are ignored for compatibility:" << std::endl;
+    ScopedIndentation si(&vios);
+    for (auto ign : ignore_list_) {
+      vios.Stream() << ign << std::endl;
+    }
   }
 }
 
diff --git a/cmdline/detail/cmdline_parse_argument_detail.h b/cmdline/detail/cmdline_parse_argument_detail.h
index f5cbda9..0f73a76 100644
--- a/cmdline/detail/cmdline_parse_argument_detail.h
+++ b/cmdline/detail/cmdline_parse_argument_detail.h
@@ -145,6 +145,8 @@
 
   template <typename T = TArg>  // Necessary to get SFINAE to kick in.
   void DumpHelp(VariableIndentationOutputStream& vios) {
+    // Separate arguments
+    vios.Stream() << std::endl;
     for (auto cname : names_) {
       std::string_view name = cname;
       auto& os = vios.Stream();
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index e80fb46..fcbc0f2 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -31,17 +31,29 @@
 
 namespace art {
 
+template <>
+struct CmdlineType<CompilerFilter::Filter> : CmdlineTypeParser<CompilerFilter::Filter> {
+  Result Parse(const std::string& option) {
+    CompilerFilter::Filter compiler_filter;
+    if (!CompilerFilter::ParseCompilerFilter(option.c_str(), &compiler_filter)) {
+      return Result::Failure(
+          android::base::StringPrintf("Unknown --compiler-filter value %s", option.c_str()));
+    }
+    return Result::Success(compiler_filter);
+  }
+
+  static const char* Name() {
+    return "CompilerFilter";
+  }
+  static const char* DescribeType() {
+    return CompilerFilter::DescribeOptions();
+  }
+};
+
 template <class Base>
 inline bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string* error_msg) {
   if (map.Exists(Base::CompilerFilter)) {
-    CompilerFilter::Filter compiler_filter;
-    if (!CompilerFilter::ParseCompilerFilter(map.Get(Base::CompilerFilter)->c_str(),
-                                             &compiler_filter)) {
-      *error_msg = android::base::StringPrintf("Unknown --compiler-filter value %s",
-                                               map.Get(Base::CompilerFilter)->c_str());
-      return false;
-    }
-    options->SetCompilerFilter(compiler_filter);
+    options->SetCompilerFilter(*map.Get(Base::CompilerFilter));
   }
   map.AssignIfExists(Base::CompileArtTest, &options->compile_art_test_);
   map.AssignIfExists(Base::HugeMethodMaxThreshold, &options->huge_method_threshold_);
@@ -108,7 +120,9 @@
 inline void AddCompilerOptionsArgumentParserOptions(Builder& b) {
   b.
       Define("--compiler-filter=_")
-          .template WithType<std::string>()
+          .template WithType<CompilerFilter::Filter>()
+          .WithHelp("Select compiler filter\n"
+                    "Default: speed-profile if profile provided, speed otherwise")
           .IntoKey(Map::CompilerFilter)
 
       .Define({"--compile-art-test", "--no-compile-art-test"})
@@ -116,31 +130,49 @@
           .IntoKey(Map::CompileArtTest)
       .Define("--huge-method-max=_")
           .template WithType<unsigned int>()
+          .WithHelp("threshold size for a huge method for compiler filter tuning.")
           .IntoKey(Map::HugeMethodMaxThreshold)
       .Define("--large-method-max=_")
           .template WithType<unsigned int>()
+          .WithHelp("threshold size for a large method for compiler filter tuning.")
           .IntoKey(Map::LargeMethodMaxThreshold)
       .Define("--num-dex-methods=_")
           .template WithType<unsigned int>()
+          .WithHelp("threshold size for a small dex file for compiler filter tuning. If the input\n"
+                    "has fewer than this many methods and the filter is not interpret-only or\n"
+                    "verify-none or verify-at-runtime, overrides the filter to use speed")
           .IntoKey(Map::NumDexMethodsThreshold)
       .Define("--inline-max-code-units=_")
           .template WithType<unsigned int>()
+          .WithHelp("the maximum code units that a methodcan have to be considered for inlining.\n"
+                    "A zero value will disable inlining. Honored only by Optimizing. Has priority\n"
+                    "over the --compiler-filter option. Intended for development/experimental use.")
           .IntoKey(Map::InlineMaxCodeUnitsThreshold)
 
       .Define({"--generate-debug-info", "-g", "--no-generate-debug-info"})
           .WithValues({true, true, false})
+          .WithHelp("Generate (or don't generate) debug information for native debugging, such as\n"
+                    "stack unwinding information, ELF symbols and dwarf sections. If used without\n"
+                    "--debuggable it will be best effort only. Does not affect the generated\n"
+                    "code. Disabled by default.")
           .IntoKey(Map::GenerateDebugInfo)
       .Define({"--generate-mini-debug-info", "--no-generate-mini-debug-info"})
           .WithValues({true, false})
+          .WithHelp("Whether or not to generate minimal amount of LZMA-compressed debug\n"
+                    "information necessary to print backtraces (disabled by default).")
           .IntoKey(Map::GenerateMiniDebugInfo)
 
       .Define({"--generate-build-id", "--no-generate-build-id"})
           .WithValues({true, false})
+          .WithHelp("Generate GNU-compatible linker build ID ELF section with SHA-1 of the file\n"
+                    "content (and thus stable across identical builds)")
           .IntoKey(Map::GenerateBuildID)
 
       .Define({"--deduplicate-code=_"})
           .template WithType<bool>()
           .WithValueMap({{"false", false}, {"true", true}})
+          .WithHelp("enable|disable code deduplication. Deduplicated code will have an arbitrary\n"
+                    "symbol tagged with [DEDUPED].")
           .IntoKey(Map::DeduplicateCode)
 
       .Define({"--count-hotness-in-compiled-code"})
@@ -153,18 +185,24 @@
           .IntoKey(Map::CheckProfiledMethods)
 
       .Define({"--dump-timings"})
+          .WithHelp("Display a breakdown of where time was spent.")
           .IntoKey(Map::DumpTimings)
 
       .Define({"--dump-pass-timings"})
+          .WithHelp("Display a breakdown time spent in optimization passes for each compiled"
+                    " method.")
           .IntoKey(Map::DumpPassTimings)
 
       .Define({"--dump-stats"})
+          .WithHelp("Display overall compilation statistics.")
           .IntoKey(Map::DumpStats)
 
       .Define("--debuggable")
+          .WithHelp("Produce code debuggable with a java-debugger.")
           .IntoKey(Map::Debuggable)
 
       .Define("--baseline")
+          .WithHelp("Produce code using the baseline compilation")
           .IntoKey(Map::Baseline)
 
       .Define("--top-k-profile-threshold=_")
@@ -184,8 +222,12 @@
 
       .Define("--dump-cfg=_")
           .template WithType<std::string>()
+          .WithHelp("Dump control-flow graphs (CFGs) to specified file.")
           .IntoKey(Map::DumpCFG)
       .Define("--dump-cfg-append")
+          .WithHelp("when dumping CFGs to an existing file, append new CFG data to existing data\n"
+                    "(instead of overwriting existing data with new data, which is the default\n"
+                    "behavior). This option is only meaningful when used with --dump-cfg.")
           .IntoKey(Map::DumpCFGAppend)
 
       .Define("--register-allocation-strategy=_")
@@ -195,6 +237,8 @@
       .Define("--resolve-startup-const-strings=_")
           .template WithType<bool>()
           .WithValueMap({{"false", false}, {"true", true}})
+          .WithHelp("If true, the compiler eagerly resolves strings referenced from const-string\n"
+                    "of startup methods.")
           .IntoKey(Map::ResolveStartupConstStrings)
 
       .Define("--initialize-app-image-classes=_")
@@ -204,10 +248,13 @@
 
       .Define("--verbose-methods=_")
           .template WithType<ParseStringList<','>>()
+          .WithHelp("Restrict the dumped CFG data to methods whose name is listed.\n"
+                    "Eg: --verbose-methods=toString,hashCode")
           .IntoKey(Map::VerboseMethods)
 
       .Define("--max-image-block-size=_")
           .template WithType<unsigned int>()
+          .WithHelp("Maximum solid block size for compressed images.")
           .IntoKey(Map::MaxImageBlockSize);
 }
 
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index 40a6284..b1398c9 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -36,7 +36,7 @@
 // Parse-able keys from the command line.
 
 // TODO: Add type parser.
-COMPILER_OPTIONS_KEY (std::string,                 CompilerFilter)
+COMPILER_OPTIONS_KEY (CompilerFilter::Filter,      CompilerFilter)
 COMPILER_OPTIONS_KEY (bool,                        CompileArtTest)
 COMPILER_OPTIONS_KEY (Unit,                        PIC)
 COMPILER_OPTIONS_KEY (unsigned int,                HugeMethodMaxThreshold)
diff --git a/compiler/driver/compiler_options_map.h b/compiler/driver/compiler_options_map.h
index af212d6..14f5112 100644
--- a/compiler/driver/compiler_options_map.h
+++ b/compiler/driver/compiler_options_map.h
@@ -22,6 +22,7 @@
 
 #include "base/variant_map.h"
 #include "cmdline_types.h"
+#include "compiler_filter.h"
 
 namespace art {
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3e0bb88..fe826c1 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -230,307 +230,12 @@
 
   UsageError("Usage: dex2oat [options]...");
   UsageError("");
-  UsageError("  -j<number>: specifies the number of threads used for compilation.");
-  UsageError("       Default is the number of detected hardware threads available on the");
-  UsageError("       host system.");
-  UsageError("      Example: -j12");
-  UsageError("");
-  UsageError("  --cpu-set=<set>: sets the cpu affinity to <set>. The <set> argument is a comma");
-  UsageError("    separated list of CPUs.");
-  UsageError("    Example: --cpu-set=0,1,2,3");
-  UsageError("");
-  UsageError("  --dex-file=<dex-file>: specifies a .dex, .jar, or .apk file to compile.");
-  UsageError("      Example: --dex-file=/system/framework/core.jar");
-  UsageError("");
-  UsageError("  --dex-location=<dex-location>: specifies an alternative dex location to");
-  UsageError("      encode in the oat file for the corresponding --dex-file argument.");
-  UsageError("      Example: --dex-file=/home/build/out/system/framework/core.jar");
-  UsageError("               --dex-location=/system/framework/core.jar");
-  UsageError("");
-  UsageError("  --zip-fd=<file-descriptor>: specifies a file descriptor of a zip file");
-  UsageError("      containing a classes.dex file to compile.");
-  UsageError("      Example: --zip-fd=5");
-  UsageError("");
-  UsageError("  --zip-location=<zip-location>: specifies a symbolic name for the file");
-  UsageError("      corresponding to the file descriptor specified by --zip-fd.");
-  UsageError("      Example: --zip-location=/system/app/Calculator.apk");
-  UsageError("");
-  UsageError("  --oat-file=<file.oat>: specifies an oat output destination via a filename.");
-  UsageError("      Example: --oat-file=/system/framework/boot.oat");
-  UsageError("");
-  UsageError("  --oat-symbols=<file.oat>: specifies a symbolized oat output destination.");
-  UsageError("      Example: --oat-file=symbols/system/framework/boot.oat");
-  UsageError("");
-  UsageError("  --oat-fd=<number>: specifies the oat output destination via a file descriptor.");
-  UsageError("      Example: --oat-fd=6");
-  UsageError("");
-  UsageError("  --input-vdex-fd=<number>: specifies the vdex input source via a file descriptor.");
-  UsageError("      Example: --input-vdex-fd=6");
-  UsageError("");
-  UsageError("  --output-vdex-fd=<number>: specifies the vdex output destination via a file");
-  UsageError("      descriptor.");
-  UsageError("      Example: --output-vdex-fd=6");
-  UsageError("");
-  UsageError("  --oat-location=<oat-name>: specifies a symbolic name for the file corresponding");
-  UsageError("      to the file descriptor specified by --oat-fd.");
-  UsageError("      Example: --oat-location=/data/dalvik-cache/system@app@Calculator.apk.oat");
-  UsageError("");
-  UsageError("  --oat-symbols=<file.oat>: specifies a destination where the oat file is copied.");
-  UsageError("      This is equivalent to file copy as build post-processing step.");
-  UsageError("      It is intended to be used with --strip and it happens before it.");
-  UsageError("      Example: --oat-symbols=/symbols/system/framework/boot.oat");
-  UsageError("");
-  UsageError("  --strip: remove all debugging sections at the end (but keep mini-debug-info).");
-  UsageError("      This is equivalent to the \"strip\" command as build post-processing step.");
-  UsageError("      It is intended to be used with --oat-symbols and it happens after it.");
-  UsageError("      Example: --oat-symbols=/symbols/system/framework/boot.oat");
-  UsageError("");
-  UsageError("  --image=<file.art>: specifies an output image filename.");
-  UsageError("      Example: --image=/system/framework/boot.art");
-  UsageError("");
-  UsageError("  --image-fd=<number>: same as --image but accepts a file descriptor instead.");
-  UsageError("      Cannot be used together with --image.");
-  UsageError("");
-  UsageError("  --image-format=(uncompressed|lz4|lz4hc):");
-  UsageError("      Which format to store the image.");
-  UsageError("      Example: --image-format=lz4");
-  UsageError("      Default: uncompressed");
-  UsageError("");
-  UsageError("  --base=<hex-address>: specifies the base address when creating a boot image.");
-  UsageError("      Example: --base=0x50000000");
-  UsageError("");
-  UsageError("  --boot-image=<file.art>: provide the image file for the boot class path.");
-  UsageError("      Do not include the arch as part of the name, it is added automatically.");
-  UsageError("      Example: --boot-image=/system/framework/boot.art");
-  UsageError("               (specifies /system/framework/<arch>/boot.art as the image file)");
-  UsageError("      Example: --boot-image=boot.art:boot-framework.art");
-  UsageError("               (specifies <bcp-path1>/<arch>/boot.art as the image file and");
-  UsageError("               <bcp-path2>/<arch>/boot-framework.art as the image extension file");
-  UsageError("               with paths taken from corresponding boot class path components)");
-  UsageError("      Example: --boot-image=/apex/com.android.art/boot.art:/system/framework/*:*");
-  UsageError("               (specifies /apex/com.android.art/<arch>/boot.art as the image");
-  UsageError("               file and search for extensions in /framework/system and boot");
-  UsageError("               class path components' paths)");
-  UsageError("      Default: $ANDROID_ROOT/system/framework/boot.art");
-  UsageError("");
-  UsageError("  --android-root=<path>: used to locate libraries for portable linking.");
-  UsageError("      Example: --android-root=out/host/linux-x86");
-  UsageError("      Default: $ANDROID_ROOT");
-  UsageError("");
-  UsageError("  --instruction-set=(arm|arm64|x86|x86_64): compile for a particular");
-  UsageError("      instruction set.");
-  UsageError("      Example: --instruction-set=x86");
-  UsageError("      Default: arm");
-  UsageError("");
-  UsageError("  --instruction-set-features=...,: Specify instruction set features");
-  UsageError("      On target the value 'runtime' can be used to detect features at run time.");
-  UsageError("      If target does not support run-time detection the value 'runtime'");
-  UsageError("      has the same effect as the value 'default'.");
-  UsageError("      Note: the value 'runtime' has no effect if it is used on host.");
-  UsageError("      Example: --instruction-set-features=div");
-  UsageError("      Default: default");
-  UsageError("");
-  UsageError("  --compiler-backend=(Quick|Optimizing): select compiler backend");
-  UsageError("      set.");
-  UsageError("      Example: --compiler-backend=Optimizing");
-  UsageError("      Default: Optimizing");
-  UsageError("");
-  UsageError("  --compiler-filter="
-                "(assume-verified"
-                "|extract"
-                "|verify"
-                "|quicken"
-                "|space-profile"
-                "|space"
-                "|speed-profile"
-                "|speed"
-                "|everything-profile"
-                "|everything):");
-  UsageError("      select compiler filter.");
-  UsageError("      Example: --compiler-filter=everything");
-  UsageError("      Default: speed-profile if --profile-file or --profile-file-fd is used,");
-  UsageError("               speed otherwise");
-  UsageError("");
-  UsageError("  --huge-method-max=<method-instruction-count>: threshold size for a huge");
-  UsageError("      method for compiler filter tuning.");
-  UsageError("      Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold);
-  UsageError("      Default: %d", CompilerOptions::kDefaultHugeMethodThreshold);
-  UsageError("");
-  UsageError("  --large-method-max=<method-instruction-count>: threshold size for a large");
-  UsageError("      method for compiler filter tuning.");
-  UsageError("      Example: --large-method-max=%d", CompilerOptions::kDefaultLargeMethodThreshold);
-  UsageError("      Default: %d", CompilerOptions::kDefaultLargeMethodThreshold);
-  UsageError("");
-  UsageError("  --num-dex-methods=<method-count>: threshold size for a small dex file for");
-  UsageError("      compiler filter tuning. If the input has fewer than this many methods");
-  UsageError("      and the filter is not interpret-only or verify-none or verify-at-runtime, ");
-  UsageError("      overrides the filter to use speed");
-  UsageError("      Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold);
-  UsageError("      Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold);
-  UsageError("");
-  UsageError("  --inline-max-code-units=<code-units-count>: the maximum code units that a method");
-  UsageError("      can have to be considered for inlining. A zero value will disable inlining.");
-  UsageError("      Honored only by Optimizing. Has priority over the --compiler-filter option.");
-  UsageError("      Intended for development/experimental use.");
-  UsageError("      Example: --inline-max-code-units=%d",
-             CompilerOptions::kDefaultInlineMaxCodeUnits);
-  UsageError("      Default: %d", CompilerOptions::kDefaultInlineMaxCodeUnits);
-  UsageError("");
-  UsageError("  --dump-timings: display a breakdown of where time was spent");
-  UsageError("");
-  UsageError("  --dump-pass-timings: display a breakdown of time spent in optimization");
-  UsageError("      passes for each compiled method.");
-  UsageError("");
-  UsageError("  -g");
-  UsageError("  --generate-debug-info: Generate debug information for native debugging,");
-  UsageError("      such as stack unwinding information, ELF symbols and DWARF sections.");
-  UsageError("      If used without --debuggable, it will be best-effort only.");
-  UsageError("      This option does not affect the generated code. (disabled by default)");
-  UsageError("");
-  UsageError("  --no-generate-debug-info: Do not generate debug information for native debugging.");
-  UsageError("");
-  UsageError("  --generate-mini-debug-info: Generate minimal amount of LZMA-compressed");
-  UsageError("      debug information necessary to print backtraces. (disabled by default)");
-  UsageError("");
-  UsageError("  --no-generate-mini-debug-info: Do not generate backtrace info.");
-  UsageError("");
-  UsageError("  --generate-build-id: Generate GNU-compatible linker build ID ELF section with");
-  UsageError("      SHA-1 of the file content (and thus stable across identical builds)");
-  UsageError("");
-  UsageError("  --no-generate-build-id: Do not generate the build ID ELF section.");
-  UsageError("");
-  UsageError("  --debuggable: Produce code debuggable with Java debugger.");
-  UsageError("");
-  UsageError("  --avoid-storing-invocation: Avoid storing the invocation args in the key value");
-  UsageError("      store. Used to test determinism with different args.");
-  UsageError("");
-  UsageError("  --write-invocation-to=<file>: Write the invocation commandline to the given file");
-  UsageError("      for later use. Used to test determinism with different host architectures.");
-  UsageError("");
-  UsageError("  --runtime-arg <argument>: used to specify various arguments for the runtime,");
-  UsageError("      such as initial heap size, maximum heap size, and verbose output.");
-  UsageError("      Use a separate --runtime-arg switch for each argument.");
-  UsageError("      Example: --runtime-arg -Xms256m");
-  UsageError("");
-  UsageError("  --profile-file=<filename>: specify profiler output file to use for compilation.");
-  UsageError("");
-  UsageError("  --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor.");
-  UsageError("      Cannot be used together with --profile-file.");
-  UsageError("");
-  UsageError("  --swap-file=<file-name>: specifies a file to use for swap.");
-  UsageError("      Example: --swap-file=/data/tmp/swap.001");
-  UsageError("");
-  UsageError("  --swap-fd=<file-descriptor>: specifies a file to use for swap (by descriptor).");
-  UsageError("      Example: --swap-fd=10");
-  UsageError("");
-  UsageError("  --swap-dex-size-threshold=<size>: specifies the minimum total dex file size in");
-  UsageError("      bytes to allow the use of swap.");
-  UsageError("      Example: --swap-dex-size-threshold=1000000");
-  UsageError("      Default: %zu", kDefaultMinDexFileCumulativeSizeForSwap);
-  UsageError("");
-  UsageError("  --swap-dex-count-threshold=<count>: specifies the minimum number of dex files to");
-  UsageError("      allow the use of swap.");
-  UsageError("      Example: --swap-dex-count-threshold=10");
-  UsageError("      Default: %zu", kDefaultMinDexFilesForSwap);
-  UsageError("");
-  UsageError("  --very-large-app-threshold=<size>: specifies the minimum total dex file size in");
-  UsageError("      bytes to consider the input \"very large\" and reduce compilation done.");
-  UsageError("      Example: --very-large-app-threshold=100000000");
-  UsageError("");
-  UsageError("  --app-image-fd=<file-descriptor>: specify output file descriptor for app image.");
-  UsageError("      The image is non-empty only if a profile is passed in.");
-  UsageError("      Example: --app-image-fd=10");
-  UsageError("");
-  UsageError("  --app-image-file=<file-name>: specify a file name for app image.");
-  UsageError("      Example: --app-image-file=/data/dalvik-cache/system@app@Calculator.apk.art");
-  UsageError("");
-  UsageError("  --multi-image: specify that separate oat and image files be generated for ");
-  UsageError("      each input dex file; the default for boot image and boot image extension.");
-  UsageError("");
-  UsageError("  --single-image: specify that a single oat and image file be generated for ");
-  UsageError("      all input dex files; the default for app image.");
-  UsageError("");
-  UsageError("  --force-determinism: force the compiler to emit a deterministic output.");
-  UsageError("");
-  UsageError("  --dump-cfg=<cfg-file>: dump control-flow graphs (CFGs) to specified file.");
-  UsageError("      Example: --dump-cfg=output.cfg");
-  UsageError("");
-  UsageError("  --dump-cfg-append: when dumping CFGs to an existing file, append new CFG data to");
-  UsageError("      existing data (instead of overwriting existing data with new data, which is");
-  UsageError("      the default behavior). This option is only meaningful when used with");
-  UsageError("      --dump-cfg.");
-  UsageError("");
-  UsageError("  --verbose-methods=<method-names>: Restrict dumped CFG data to methods whose name");
-  UsageError("      contain one of the method names passed as argument");
-  UsageError("      Example: --verbose-methods=toString,hashCode");
-  UsageError("");
-  UsageError("  --classpath-dir=<directory-path>: directory used to resolve relative class paths.");
-  UsageError("");
-  UsageError("  --class-loader-context=<string spec>: a string specifying the intended");
-  UsageError("      runtime loading context for the compiled dex files.");
-  UsageError("");
-  UsageError("  --stored-class-loader-context=<string spec>: a string specifying the intended");
-  UsageError("      runtime loading context that is stored in the oat file. Overrides");
-  UsageError("      --class-loader-context. Note that this ignores the classpath_dir arg.");
-  UsageError("");
-  UsageError("      It describes how the class loader chain should be built in order to ensure");
-  UsageError("      classes are resolved during dex2aot as they would be resolved at runtime.");
-  UsageError("      This spec will be encoded in the oat file. If at runtime the dex file is");
-  UsageError("      loaded in a different context, the oat file will be rejected.");
-  UsageError("");
-  UsageError("      The chain is interpreted in the natural 'parent order', meaning that class");
-  UsageError("      loader 'i+1' will be the parent of class loader 'i'.");
-  UsageError("      The compilation sources will be appended to the classpath of the first class");
-  UsageError("      loader.");
-  UsageError("");
-  UsageError("      E.g. if the context is 'PCL[lib1.dex];DLC[lib2.dex]' and ");
-  UsageError("      --dex-file=src.dex then dex2oat will setup a PathClassLoader with classpath ");
-  UsageError("      'lib1.dex:src.dex' and set its parent to a DelegateLastClassLoader with ");
-  UsageError("      classpath 'lib2.dex'.");
-  UsageError("");
-  UsageError("      Note that the compiler will be tolerant if the source dex files specified");
-  UsageError("      with --dex-file are found in the classpath. The source dex files will be");
-  UsageError("      removed from any class loader's classpath possibly resulting in empty");
-  UsageError("      class loaders.");
-  UsageError("");
-  UsageError("      Example: --class-loader-context=PCL[lib1.dex:lib2.dex];DLC[lib3.dex]");
-  UsageError("");
-  UsageError("  --class-loader-context-fds=<fds>: a colon-separated list of file descriptors");
-  UsageError("      for dex files in --class-loader-context. Their order must be the same as");
-  UsageError("      dex files in flattened class loader context.");
-  UsageError("");
-  UsageError("  --dirty-image-objects=<file-path>: list of known dirty objects in the image.");
-  UsageError("      The image writer will group them together.");
-  UsageError("");
-  UsageError("  --updatable-bcp-packages-file=<file-path>: file with a list of updatable");
-  UsageError("      boot class path packages. Classes in these packages and sub-packages");
-  UsageError("      shall not be resolved during app compilation to avoid AOT assumptions");
-  UsageError("      being invalidated after applying updates to these components.");
-  UsageError("");
-  UsageError("  --compact-dex-level=none|fast: None avoids generating compact dex, fast");
-  UsageError("      generates compact dex with low compile time. If speed-profile is specified as");
-  UsageError("      the compiler filter and the profile is not empty, the default compact dex");
-  UsageError("      level is always used.");
-  UsageError("");
-  UsageError("  --deduplicate-code=true|false: enable|disable code deduplication. Deduplicated");
-  UsageError("      code will have an arbitrary symbol tagged with [DEDUPED].");
-  UsageError("");
-  UsageError("  --copy-dex-files=true|false: enable|disable copying the dex files into the");
-  UsageError("      output vdex.");
-  UsageError("");
-  UsageError("  --compilation-reason=<string>: optional metadata specifying the reason for");
-  UsageError("      compiling the apk. If specified, the string will be embedded verbatim in");
-  UsageError("      the key value store of the oat file.");
-  UsageError("      Example: --compilation-reason=install");
-  UsageError("");
-  UsageError("  --resolve-startup-const-strings=true|false: If true, the compiler eagerly");
-  UsageError("      resolves strings referenced from const-string of startup methods.");
-  UsageError("");
-  UsageError("  --max-image-block-size=<size>: Maximum solid block size for compressed images.");
-  UsageError("");
-  UsageError("  --compile-individually: Compiles dex files individually, unloading classes in");
-  UsageError("      between compiling each file.");
-  UsageError("");
+
+  std::stringstream oss;
+  VariableIndentationOutputStream vios(&oss);
+  auto parser = CreateDex2oatArgumentParser();
+  parser.DumpHelp(vios);
+  UsageError(oss.str().c_str());
   std::cerr << "See log for usage error information\n";
   exit(EXIT_FAILURE);
 }
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 81b9c98..c7c62d7 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -34,6 +34,7 @@
   }
 
   static const char* Name() { return "InstructionSet"; }
+  static const char* DescribeType() { return "arm|arm64|x86|x86_64|none"; }
 };
 
 #define COMPILER_OPTIONS_MAP_TYPE Dex2oatArgumentMap
@@ -57,18 +58,44 @@
   builder.
       Define("--dex-file=_")
           .WithType<std::vector<std::string>>().AppendValues()
+          .WithHelp("Specifies a .dex, .jar, or .apk file to compile.\n"
+                    "Eg: --dex-file=/system/framework/core.jar")
+          .WithMetavar("<dex-file>")
           .IntoKey(M::DexFiles)
       .Define("--dex-location=_")
           .WithType<std::vector<std::string>>().AppendValues()
+          .WithMetavar("<dex-location>")
+          .WithHelp("specifies an alternative dex location to encode in the oat file for the\n"
+                    "corresponding --dex-file argument. The first --dex-location corresponds to\n"
+                    "the first --dex-file, the second to the second and so on.\n"
+                    "Eg: --dex-file=/home/build/out/system/framework/core.jar\n"
+                    "    --dex-location=/system/framework/core.jar")
           .IntoKey(M::DexLocations)
       .Define("--zip-fd=_")
           .WithType<int>()
+          .WithHelp("specifies a file descriptor of a zip file containing a classes.dex file to\n"
+                    "compile. Eg: --zip-fd=5")
           .IntoKey(M::ZipFd)
       .Define("--zip-location=_")
           .WithType<std::string>()
+          .WithHelp("Specifies a symbolic name for the file corresponding to the FD given by\n"
+                    "--zip-fd.")
           .IntoKey(M::ZipLocation)
       .Define("--boot-image=_")
           .WithType<std::string>()
+          .WithHelp("provide the image file for the boot class path.\n"
+                    "Do not include the arch as part of the name, it is added automatically.\n"
+                    "Example: --boot-image=/system/framework/boot.art\n"
+                    "         (specifies /system/framework/<arch>/boot.art as the image file)\n"
+                    "Example: --boot-image=boot.art:boot-framework.art\n"
+                    "         (specifies <bcp-path1>/<arch>/boot.art as the image file and\n"
+                    "         <bcp-path2>/<arch>/boot-framework.art as the image extension file\n"
+                    "         with paths taken from corresponding boot class path components)\n"
+                    "Example: --boot-image=/apex/com.android.art/boot.art:/system/framework/*:*\n"
+                    "         (specifies /apex/com.android.art/<arch>/boot.art as the image\n"
+                    "         file and search for extensions in /framework/system and boot\n"
+                    "         class path components' paths)\n"
+                    "Default: $ANDROID_ROOT/system/framework/boot.art")
           .IntoKey(M::BootImage);
 }
 
@@ -76,35 +103,53 @@
   builder.
       Define("--input-vdex-fd=_")
           .WithType<int>()
+          .WithHelp("specifies the vdex input source via a file descriptor.")
           .IntoKey(M::InputVdexFd)
       .Define("--input-vdex=_")
           .WithType<std::string>()
+          .WithHelp("specifies the vdex input source via a filename.")
           .IntoKey(M::InputVdex)
       .Define("--output-vdex-fd=_")
+          .WithHelp("specifies the vdex output destination via a file descriptor.")
           .WithType<int>()
           .IntoKey(M::OutputVdexFd)
       .Define("--output-vdex=_")
           .WithType<std::string>()
+          .WithHelp("specifies the vdex output destination via a filename.")
           .IntoKey(M::OutputVdex)
       .Define("--dm-fd=_")
           .WithType<int>()
+          .WithHelp("specifies the dm output destination via a file descriptor.")
           .IntoKey(M::DmFd)
       .Define("--dm-file=_")
           .WithType<std::string>()
+          .WithHelp("specifies the dm output destination via a filename.")
           .IntoKey(M::DmFile)
       .Define("--oat-file=_")
           .WithType<std::string>()
+          .WithHelp(" Specifies an oat output destination via a filename.\n"
+                    "Eg: --oat-file=/system/framework/boot.oat")
           .IntoKey(M::OatFile)
       .Define("--oat-symbols=_")
           .WithType<std::string>()
+          .WithHelp("Specifies a symbolized oat output destination.\n"
+                    "Eg: --oat-symbols=symbols/system/framework/boot.oat")
           .IntoKey(M::OatSymbols)
       .Define("--strip")
+          .WithHelp("remove all debugging sections at the end (but keep mini-debug-info).\n"
+                    "This is equivalent to the \"strip\" command as build post-processing step.\n"
+                    "It is intended to be used with --oat-symbols and it happens after it.\n"
+                    "Eg: --oat-symbols=/symbols/system/framework/boot.oat")
           .IntoKey(M::Strip)
       .Define("--oat-fd=_")
           .WithType<int>()
+          .WithHelp("Specifies the oat output destination via a file descriptor. Eg: --oat-fd=5")
           .IntoKey(M::OatFd)
       .Define("--oat-location=_")
           .WithType<std::string>()
+          .WithHelp("specifies a symbolic name for the file corresponding to the file descriptor\n"
+                    "specified by --oat-fd.\n"
+                    "Eg: --oat-location=/data/dalvik-cache/system@app@Calculator.apk.oat")
           .IntoKey(M::OatLocation);
 }
 
@@ -112,33 +157,52 @@
   builder.
       Define("--image=_")
           .WithType<std::string>()
+          .WithHelp("specifies an output image filename. Eg: --image=/system/framework/boot.art")
           .IntoKey(M::ImageFilename)
       .Define("--image-fd=_")
           .WithType<int>()
+          .WithHelp("specifies an output image file descriptor. Cannot be used with --image.\n"
+                    "Eg: --image-fd=7")
           .IntoKey(M::ImageFd)
       .Define("--base=_")
           .WithType<std::string>()
+          .WithHelp("Specifies the base address when creating a boot image. Eg: --base=0x50000000")
+          .WithMetavar("{hex address}")
           .IntoKey(M::Base)
       .Define("--app-image-file=_")
           .WithType<std::string>()
+          .WithHelp("Specify a file name for app image. Only used if a profile is passed in.")
           .IntoKey(M::AppImageFile)
       .Define("--app-image-fd=_")
           .WithType<int>()
+          .WithHelp("Specify a file descriptor for app image. Only used if a profile is passed in.")
           .IntoKey(M::AppImageFileFd)
       .Define({"--multi-image", "--single-image"})
           .WithValues({true, false})
+          .WithHelp("Specifies if separate oat and image files should be generated for each dex\n"
+                    "file. --multi-image is default for boot image and --single-image for app\n"
+                    "images.")
           .IntoKey(M::MultiImage)
       .Define("--dirty-image-objects=_")
           .WithType<std::string>()
+          .WithHelp("list of known dirty objects in the image. The image writer will group them"
+                    " together")
           .IntoKey(M::DirtyImageObjects)
       .Define("--updatable-bcp-packages-file=_")
           .WithType<std::string>()
+          .WithHelp("file with a list of updatable boot class path packages. Classes in these\n"
+                    "packages and sub-packages shall not be resolved during app compilation to\n"
+                    "avoid AOT assumptions being invalidated after applying updates to these\n"
+                    "components."
+          )
           .IntoKey(M::UpdatableBcpPackagesFile)
       .Define("--image-format=_")
           .WithType<ImageHeader::StorageMode>()
           .WithValueMap({{"lz4", ImageHeader::kStorageModeLZ4},
                          {"lz4hc", ImageHeader::kStorageModeLZ4HC},
                          {"uncompressed", ImageHeader::kStorageModeUncompressed}})
+          .WithHelp("Which format to store the image Defaults to uncompressed. Eg:"
+                    " --image-format=lz4")
           .IntoKey(M::ImageFormat);
 }
 
@@ -146,15 +210,19 @@
   builder.
       Define("--swap-file=_")
           .WithType<std::string>()
+          .WithHelp("Specify a file to use for swap. Eg: --swap-file=/data/tmp/swap.001")
           .IntoKey(M::SwapFile)
       .Define("--swap-fd=_")
           .WithType<int>()
+          .WithHelp("Specify a file to use for swap by file-descriptor. Eg: --swap-fd=3")
           .IntoKey(M::SwapFileFd)
       .Define("--swap-dex-size-threshold=_")
           .WithType<unsigned int>()
+          .WithHelp("specifies the minimum total dex file size in bytes to allow the use of swap.")
           .IntoKey(M::SwapDexSizeThreshold)
       .Define("--swap-dex-count-threshold=_")
           .WithType<unsigned int>()
+          .WithHelp("specifies the minimum number of dex file to allow the use of swap.")
           .IntoKey(M::SwapDexCountThreshold);
 }
 
@@ -165,9 +233,11 @@
           .IntoKey(M::Passes)
       .Define("--profile-file=_")
           .WithType<std::string>()
+          .WithHelp("Specify profiler output file to use for compilation using a filename.")
           .IntoKey(M::Profile)
       .Define("--profile-file-fd=_")
           .WithType<int>()
+          .WithHelp("Specify profiler output file to use for compilation using a file-descriptor.")
           .IntoKey(M::ProfileFd)
       .Define("--no-inline-from=_")
           .WithType<std::string>()
@@ -178,16 +248,27 @@
   builder.
       Define("--instruction-set=_")
           .WithType<InstructionSet>()
+          .WithHelp("Compile for a particular instruction set.")
           .IntoKey(M::TargetInstructionSet)
       .Define("--instruction-set-variant=_")
           .WithType<std::string>()
+          .WithHelp("Specify instruction set features using variant name.\n"
+                    "Eg: --instruction-set-variant=silvermont")
+          .WithMetavar("{Variant Name}")
           .IntoKey(M::TargetInstructionSetVariant)
       .Define("--instruction-set-features=_")
           .WithType<std::string>()
+          .WithHelp("Specify instruction set features.\n"
+                    "On target the value 'runtime' can be used to detect features at run time.\n"
+                    "If target does not support run-time detection the value 'runtime'\n"
+                    "has the same effect as the value 'default'.\n"
+                    "Note: the value 'runtime' has no effect if it is used on host.\n"
+                    "Example: --instruction-set-features=div\n"
+                    "Default: default")
           .IntoKey(M::TargetInstructionSetFeatures);
 }
 
-static Parser CreateArgumentParser() {
+Parser CreateDex2oatArgumentParser() {
   std::unique_ptr<Builder> parser_builder = std::make_unique<Builder>();
 
   AddInputMappings(*parser_builder);
@@ -199,33 +280,50 @@
 
   parser_builder->
       Define({"--watch-dog", "--no-watch-dog"})
+          .WithHelp("Enable or disable the watchdog timer.")
           .WithValues({true, false})
           .IntoKey(M::Watchdog)
       .Define("--watchdog-timeout=_")
           .WithType<int>()
+          .WithHelp("Set the watchdog timeout value in seconds.")
           .IntoKey(M::WatchdogTimeout)
       .Define("-j_")
           .WithType<unsigned int>()
+          .WithHelp("specifies the number of threads used for compilation. Default is the number\n"
+                    "of detected hardware threads available on the host system.")
           .IntoKey(M::Threads)
       .Define("--cpu-set=_")
           .WithType<std::vector<int32_t>>()
+          .WithHelp("sets the cpu affinitiy to the given <set>. The <set> is a comma separated\n"
+                    "list of cpus. Eg: --cpu-set=0,1,2,3")
+          .WithMetavar("<set>")
           .IntoKey(M::CpuSet)
       .Define("--android-root=_")
           .WithType<std::string>()
+          .WithHelp("Used to locate libraries for portable linking.\n"
+                    "Eg: --android-root=out/host/linux-x86\n"
+                    "Default: $ANDROID_ROOT")
           .IntoKey(M::AndroidRoot)
       .Define("--compiler-backend=_")
           .WithType<Compiler::Kind>()
           .WithValueMap({{"Quick", Compiler::Kind::kQuick},
                          {"Optimizing", Compiler::Kind::kOptimizing}})
+          .WithHelp("Select a compiler backend set. Default: optimizing")
           .IntoKey(M::Backend)
       .Define("--host")
+          .WithHelp("Run in host mode")
           .IntoKey(M::Host)
       .Define("--avoid-storing-invocation")
+          .WithHelp("Avoid storing the invocation args in the key-value store. Used to test\n"
+                    "determinism with different args.")
           .IntoKey(M::AvoidStoringInvocation)
       .Define("--very-large-app-threshold=_")
           .WithType<unsigned int>()
+          .WithHelp("Specifies the minimum total dex file size in bytes to consider the input\n"
+                    "\"very large\" and reduce compilation done.")
           .IntoKey(M::VeryLargeAppThreshold)
       .Define("--force-determinism")
+          .WithHelp("Force the compiler to emit a deterministic output")
           .IntoKey(M::ForceDeterminism)
       .Define("--check-linkage-conditions")
           .IntoKey(M::CheckLinkageConditions)
@@ -236,34 +334,81 @@
           .WithValueMap({{"true", linker::CopyOption::kOnlyIfCompressed},
                          {"false", linker::CopyOption::kNever},
                          {"always", linker::CopyOption::kAlways}})
+          .WithHelp("enable|disable copying the dex files into the output vdex.")
           .IntoKey(M::CopyDexFiles)
       .Define("--write-invocation-to=_")
+          .WithHelp("Write the invocation commandline to the given file for later use. Used to\n"
+                    "test determinism with different args.")
           .WithType<std::string>()
           .IntoKey(M::InvocationFile)
       .Define("--classpath-dir=_")
           .WithType<std::string>()
+          .WithHelp("Directory used to resolve relative class paths.")
           .IntoKey(M::ClasspathDir)
       .Define("--class-loader-context=_")
           .WithType<std::string>()
+          .WithHelp("a string specifying the intended runtime loading context for the compiled\n"
+                    "dex files.")
           .IntoKey(M::ClassLoaderContext)
       .Define("--class-loader-context-fds=_")
           .WithType<std::string>()
+          .WithHelp("a colon-separated list of file descriptors for dex files in\n"
+                    "--class-loader-context. Their order must be the same as dex files in a\n"
+                    "flattened class loader context")
           .IntoKey(M::ClassLoaderContextFds)
       .Define("--stored-class-loader-context=_")
           .WithType<std::string>()
+          .WithHelp("a string specifying the intended runtime loading context that is stored\n"
+                    "in the oat file. Overrides --class-loader-context. Note that this ignores\n"
+                    "the classpath_dir arg.\n"
+                    "\n"
+                    "It describes how the class loader chain should be built in order to ensure\n"
+                    "classes are resolved during dex2aot as they would be resolved at runtime.\n"
+                    "This spec will be encoded in the oat file. If at runtime the dex file is\n"
+                    "loaded in a different context, the oat file will be rejected.\n"
+                    "\n"
+                    "The chain is interpreted in the natural 'parent order', meaning that class\n"
+                    "loader 'i+1' will be the parent of class loader 'i'.\n"
+                    "The compilation sources will be appended to the classpath of the first class\n"
+                    "loader.\n"
+                    "\n"
+                    "E.g. if the context is 'PCL[lib1.dex];DLC[lib2.dex]' and \n"
+                    "--dex-file=src.dex then dex2oat will setup a PathClassLoader with classpath \n"
+                    "'lib1.dex:src.dex' and set its parent to a DelegateLastClassLoader with \n"
+                    "classpath 'lib2.dex'.\n"
+                    "\n"
+                    "Note that the compiler will be tolerant if the source dex files specified\n"
+                    "with --dex-file are found in the classpath. The source dex files will be\n"
+                    "removed from any class loader's classpath possibly resulting in empty\n"
+                    "class loaders.\n"
+                    "\n"
+                    "Example: --class-loader-context=PCL[lib1.dex:lib2.dex];DLC[lib3.dex]")
           .IntoKey(M::StoredClassLoaderContext)
       .Define("--compact-dex-level=_")
           .WithType<CompactDexLevel>()
           .WithValueMap({{"none", CompactDexLevel::kCompactDexLevelNone},
                          {"fast", CompactDexLevel::kCompactDexLevelFast}})
+          .WithHelp("None avoids generating compact dex, fast generates compact dex with low\n"
+                    "compile time. If speed-profile is specified as the compiler filter and the\n"
+                    "profile is not empty, the default compact dex level is always used.")
           .IntoKey(M::CompactDexLevel)
       .Define("--runtime-arg _")
           .WithType<std::vector<std::string>>().AppendValues()
+          .WithMetavar("{dalvikvm-arg}")
+          .WithHelp("used to specify various arguments for the runtime, such as initial heap\n"
+                    "size, maximum heap size, and verbose output. Use a separate --runtime-arg\n"
+                    "switch for each argument.\n"
+                    "Example: --runtime-arg -Xms256m")
           .IntoKey(M::RuntimeOptions)
       .Define("--compilation-reason=_")
           .WithType<std::string>()
+          .WithHelp("optional metadata specifying the reason for compiling the apk. If specified,\n"
+                    "the string will be embedded verbatim in the key value store of the oat file.\n"
+                    "Example: --compilation-reason=install")
           .IntoKey(M::CompilationReason)
       .Define("--compile-individually")
+          .WithHelp("Compiles dex files individually, unloading classes in between compiling each"
+                    " file.")
           .IntoKey(M::CompileIndividually);
 
   AddCompilerOptionsArgumentParserOptions<Dex2oatArgumentMap>(*parser_builder);
@@ -276,7 +421,7 @@
 std::unique_ptr<Dex2oatArgumentMap> Dex2oatArgumentMap::Parse(int argc,
                                                               const char** argv,
                                                               std::string* error_msg) {
-  Parser parser = CreateArgumentParser();
+  Parser parser = CreateDex2oatArgumentParser();
   CmdlineResult parse_result = parser.Parse(argv, argc);
   if (!parse_result.IsSuccess()) {
     *error_msg = parse_result.GetMessage();
diff --git a/dex2oat/dex2oat_options.h b/dex2oat/dex2oat_options.h
index 27d3d25..1da1ff9 100644
--- a/dex2oat/dex2oat_options.h
+++ b/dex2oat/dex2oat_options.h
@@ -72,6 +72,8 @@
 #include "dex2oat_options.def"
 };
 
+CmdlineParser<Dex2oatArgumentMap, Dex2oatArgumentMap::Key> CreateDex2oatArgumentParser();
+
 extern template struct CompilerOptionsMap<Dex2oatArgumentMap, Dex2oatArgumentMapKey>;
 
 }  // namespace art
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index c086490..9ce2533 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -240,6 +240,11 @@
   return true;
 }
 
+const char* CompilerFilter::DescribeOptions() {
+  return "assume-verified|extract|verify|quicken|space{,-profile}|speed{,-profile}|"
+          "everything{,-profile}";
+}
+
 std::ostream& operator<<(std::ostream& os, const CompilerFilter::Filter& rhs) {
   return os << CompilerFilter::NameOfFilter(rhs);
 }
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index c36e40f..a016683 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -101,6 +101,8 @@
   // 'filter' must be non-null.
   static bool ParseCompilerFilter(const char* name, /*out*/Filter* filter);
 
+  static const char* DescribeOptions();
+
  private:
   DISALLOW_COPY_AND_ASSIGN(CompilerFilter);
 };