New PM, opt and command line options

Hi all,

I'm porting some LLVM plugins to the new pass manager and I've noticed
that the command line options are no longer registered when using
`-load-pass-plugin` (the new PM flag) to load the plugins in opt.
Everything is back to normal when loading via `-load` (the legacy PM).

For example, given this CL option:

static cl::opt<bool> SomeFlat("some-flag", cl::init(false),
cl::desc("set some flag"));

I can see that it's being registered:

opt -load MyPlugin -help | grep some-flag
   -some-flag - set some flag

However, this returns nothing:

opt -load-pass-plugin -help | grep some-flag

Am I missing something obvious? Or is that `by design`?



I think it’s just a matter of initialization order.

In the old PM, pass plugins are loaded by “-load” options, which is defined in Support/PluginLoader.
In Support/PluginLoader.h we can found that it has a custom command line options parser:
`cl::opt<PluginLoader, false, cl::parser<std::string> >`. Which would call `PluginLoader::operator=` later, which is the place where it load the dynamic libraries. All the registrations mentioned previously happened before the `main` function of opt, because the `cl::opt<>` is defined as a global static variable. And because it happened before the `main` function, by the time `cl::ParseCommandLineOptions` is called (inside the `main` function of opt), the command line subsystem already knew all of the option information defined in your plugin. Therefore it can display a correct `-help` text.

On the other hand, all of the logic for new PM in opt is defined in tools/opt/NewPMDriver.cpp. In there, dynamic libraries will not be loaded until `PassPlugin::Load(…)` is called inside the `llvm::runPassPipeline` function, which is invoked later than `cl::ParseCommandLineOptions` in the `main` function.
In another word, the options in your plugin are not displayed because your dynamic plugin library is not even loaded when the command line subsystem is trying to display the help text.

- Min

This is a very detailed and clear explanation - thank you Min!


We also hit this problem in opt (i.e. plugin options are not visible in the new PM path).
One potential solution is to reparse the command line arguments if a plugin is loaded:

-  for (auto &PluginFN : PassPlugins) {
+  if (PassPlugins.size()) {
+    SmallVector<std::string, 1> PluginList(PassPlugins.begin(), PassPlugins.end());
+    cl::ResetAllOptionOccurrences();
+    for (auto &PluginFN : PluginList) {
       auto PassPlugin = PassPlugin::Load(PluginFN);
       if (!PassPlugin) {
         errs() << "Failed to load passes from '" << PluginFN
                << "'. Request ignored.\n";
+    cl::ParseCommandLineOptions(argc, argv,
+      "llvm .bc -> .bc modular optimizer and analysis printer\n");
+  }

Also, plugin options will be flagged as “Unknown command line arguments” during the initial parse, so we’ll have to ignore them somehow.

Can I please get some feedback on the proposed solution and whether there’s a better way?


1 Like