List target backends registered by plugins in C API. (#14030)

Follow-up to https://github.com/openxla/iree/pull/13262

Plugins may register target backends, so the global registry does not
reliably enumerate all targets.

The `--iree-hal-list-target-backends` flag callback runs globally,
before session/invocation initialization and plugin activation, so it
was missing the `cuda` backend in its list. I've fixed that by creating
an internal/ephemeral `Session`.

---

Also added a new `--iree-list-plugins` CLI flag.
diff --git a/compiler/bindings/c/iree/compiler/embedding_api.h b/compiler/bindings/c/iree/compiler/embedding_api.h
index 8fd1f91..6adc18c 100644
--- a/compiler/bindings/c/iree/compiler/embedding_api.h
+++ b/compiler/bindings/c/iree/compiler/embedding_api.h
@@ -118,6 +118,9 @@
 IREE_EMBED_EXPORTED void ireeCompilerGlobalShutdown();
 
 // Invokes a callback with each registered HAL target backend.
+//
+// This is really only suitable for global CLI-like tools, as plugins may
+// register target backends and plugins are activated at the session level.
 IREE_EMBED_EXPORTED void ireeCompilerEnumerateRegisteredHALTargetBackends(
     void (*callback)(const char *backend, void *userData), void *userData);
 
diff --git a/compiler/src/iree/compiler/API/Internal/Embed.cpp b/compiler/src/iree/compiler/API/Internal/Embed.cpp
index de0da84..58839f9 100644
--- a/compiler/src/iree/compiler/API/Internal/Embed.cpp
+++ b/compiler/src/iree/compiler/API/Internal/Embed.cpp
@@ -855,14 +855,27 @@
 
 void ireeCompilerEnumerateRegisteredHALTargetBackends(
     void (*callback)(const char *backend, void *userData), void *userData) {
-  // TODO: Replace this entry point with one on the invocation where we can
+  // Note: plugins may register target backends, so the global registry does not
   // reliably enumerate all targets.
+
+  // This API is a kludge, really only suitable for global CLI-like tools.
+  // In order to maximize it's utility, we'll create an ephemeral Session and
+  // activate plugins so the list of backends is as complete as possible.
+  if (!globalInit) {
+    fprintf(stderr, "FATAL ERROR: Not initialized\n");
+    abort();
+  }
+  Session *session = new Session(*globalInit);
+  // HACK: activate plugins and ignore failures.
+  (void)session->activatePluginsOnce();
+
   auto registeredTargetBackends =
-      mlir::iree_compiler::IREE::HAL::TargetBackendRegistry::getGlobal()
-          .getRegisteredTargetBackends();
+      session->targetRegistry.getRegisteredTargetBackends();
   for (auto &b : registeredTargetBackends) {
     callback(b.c_str(), userData);
   }
+
+  delete session;
 }
 
 void ireeCompilerEnumeratePlugins(void (*callback)(const char *pluginName,
diff --git a/compiler/src/iree/compiler/Tools/iree_compile_lib.cc b/compiler/src/iree/compiler/Tools/iree_compile_lib.cc
index c0bc241..226da15 100644
--- a/compiler/src/iree/compiler/Tools/iree_compile_lib.cc
+++ b/compiler/src/iree/compiler/Tools/iree_compile_lib.cc
@@ -123,6 +123,18 @@
             nullptr);
         exit(0);
       }));
+  llvm::cl::opt<bool> listPlugins(
+      "iree-list-plugins", llvm::cl::desc("Lists all loaded plugins."),
+      llvm::cl::init(false), llvm::cl::ValueDisallowed,
+      llvm::cl::callback([&](const bool &) {
+        llvm::outs() << "Loaded plugins:\n";
+        ireeCompilerEnumeratePlugins(
+            [](const char *pluginName, void *userData) {
+              llvm::outs() << "  " << pluginName << "\n";
+            },
+            nullptr);
+        exit(0);
+      }));
 
   ireeCompilerGlobalInitialize();
   ireeCompilerGetProcessCLArgs(&argc, const_cast<const char ***>(&argv));
@@ -130,12 +142,6 @@
                             "IREE compilation driver\n",
                             /*installSignalHandlers=*/true);
 
-  // If a HAL executable is being compiled, it is only valid to output in that
-  // form.
-  if (compileMode == CompileMode::hal_executable) {
-    outputFormat = OutputFormat::hal_executable;
-  }
-
   // Stash our globals in an RAII instance.
   struct MainState {
     iree_compiler_session_t *session = ireeCompilerSessionCreate();
@@ -197,6 +203,8 @@
     case CompileMode::vm:
       break;
     case CompileMode::hal_executable: {
+      // Compiling a HAL executable, it is only valid to output in that form.
+      outputFormat = OutputFormat::hal_executable;
       if (!ireeCompilerInvocationPipeline(
               r.inv, IREE_COMPILER_PIPELINE_HAL_EXECUTABLE))
         return false;
diff --git a/docs/website/docs/guides/deployment-configurations/index.md b/docs/website/docs/guides/deployment-configurations/index.md
index d6fbb9a..e647a5d 100644
--- a/docs/website/docs/guides/deployment-configurations/index.md
+++ b/docs/website/docs/guides/deployment-configurations/index.md
@@ -48,6 +48,7 @@
         $ iree-compile --iree-hal-list-target-backends
 
         Registered target backends:
+            cuda
             llvm-cpu
             metal
             metal-spirv