Add API to create passes out of a list of command-line flags.

This re-implements the -Oconfig=<file> flag to use a new API that takes
a list of command-line flags representing optimization passes.

This moves the processing of flags that create new optimization passes
out of spirv-opt and into the library API.  Useful for other tools that
want to incorporate a facility similar to -Oconfig.

The main changes are:

1- Add a new public function Optimizer::RegisterPassesFromFlags. This
   takes a vector of strings.  Each string is assumed to have the form
   '--pass_name[=pass_args]'.  It creates and registers into the pass
   manager all the passes specified in the vector.  Each pass is
   validated internally.  Failure to create a pass instance causes the
   function to return false and a diagnostic is emitted to the
   registered message consumer.

2- Re-implements -Oconfig in spirv-opt to use the new API.
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index e1eeedf..6e193bd 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -83,6 +83,9 @@
   // invoked once for each message communicated from the library.
   void SetMessageConsumer(MessageConsumer consumer);
 
+  // Returns a reference to the registered message consumer.
+  const MessageConsumer& consumer() const;
+
   // Registers the given |pass| to this optimizer. Passes will be run in the
   // exact order of registration. The token passed in will be consumed by this
   // method.
@@ -100,14 +103,51 @@
 
   // Registers passes that attempt to legalize the generated code.
   //
-  // Note: this recipe is specially for legalizing SPIR-V. It should be used
-  // by compilers after translating HLSL source code literally. It should
+  // Note: this recipe is specially designed for legalizing SPIR-V. It should be
+  // used by compilers after translating HLSL source code literally. It should
   // *not* be used by general workloads for performance or size improvement.
   //
   // This sequence of passes is subject to constant review and will change
   // from time to time.
   Optimizer& RegisterLegalizationPasses();
 
+  // Register passes specified in the list of |flags|.  Each flag must be a
+  // string of a form accepted by Optimizer::FlagHasValidForm().
+  //
+  // If the list of flags contains an invalid entry, it returns false and an
+  // error message is emitted to the MessageConsumer object (use
+  // Optimizer::SetMessageConsumer to define a message consumer, if needed).
+  //
+  // If all the passes are registered successfully, it returns true.
+  bool RegisterPassesFromFlags(const std::vector<std::string>& flags);
+
+  // Registers the optimization pass associated with |flag|.  This only accepts
+  // |flag| values of the form "--pass_name[=pass_args]".  If no such pass
+  // exists, it returns false.  Otherwise, the pass is registered and it returns
+  // true.
+  //
+  // The following flags have special meaning:
+  //
+  // -O: Registers all performance optimization passes
+  //     (Optimizer::RegisterPerformancePasses)
+  //
+  // -Os: Registers all size optimization passes
+  //      (Optimizer::RegisterSizePasses).
+  //
+  // --legalize-hlsl: Registers all passes that legalize SPIR-V generated by an
+  //                  HLSL front-end.
+  bool RegisterPassFromFlag(const std::string& flag);
+
+  // Validates that |flag| has a valid format.  Strings accepted:
+  //
+  // --pass_name[=pass_args]
+  // -O
+  // -Os
+  //
+  // If |flag| takes one of the forms above, it returns true.  Otherwise, it
+  // returns false.
+  bool FlagHasValidForm(const std::string& flag) const;
+
   // Optimizes the given SPIR-V module |original_binary| and writes the
   // optimized binary into |optimized_binary|.
   // Returns true on successful optimization, whether or not the module is