[PATCH] D105959: Use ManagedStatic and lazy initialization of cl::opt in libSupport to make it free of global initializer

Duncan P. N. Exon Smith via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 16 11:19:05 PDT 2021


dexonsmith added a comment.

In D105959#2882136 <https://reviews.llvm.org/D105959#2882136>, @mehdi_amini wrote:

> In D105959#2882099 <https://reviews.llvm.org/D105959#2882099>, @bondhugula wrote:
>
>> This is a really welcome change! Multiple registration issues were really an inconvenience - I had no clue this was the pattern to use to fix it. Thanks!
>
> To be fair: we can do it transparently only for libSupport, as it contains the entry point for command line parsing it can explicitly trigger the registration of the options for itself. Other libraries in LLVM don't have this luxury...

We could probably combine this with the technique used to avoid static constructors in compiler-rt/lib/profile to pick up other libraries in the same final linked image. The idea would be to ask the linker to build an array of initializer functions that LLVMSupport could iterate through to initialize options it doesn't know about.

For example, on Darwin, this code adds an initializer to a global array in section `__DATA,__llvmopts`:

  using OptionConstructorT = void (*)(); // Declared in LLVMSupport headers to get safety.
  
  void initOptions();
  
  // Add an options constructor the array of cl::opt initializers.
  __attribute__((section("__DATA,__llvmopts"),visibility("hidden")))
  OptionConstructorT OptionsConstructor = initOptions;

Also on Darwin, this could go in LLVMSupport to access it:

  using OptionConstructorT = void (*)(); // Declared in LLVMSupport headers to get safety.
  
  // Declare symbols to access the global array.
  extern OptionConstructorT *ExternalOptionsInitBegin
    __asm("section$start$__DATA$__llvmopts");
  extern OptionConstructorT *ExternalOptionsInitEnd
    __asm("section$end$__DATA$__llvmopts");
  
  void initCommonOptions();
  void initOptions() {
    initCommonOptions();
    // Iterate through external initializers for options.
    for (auto I = ExternalOptionsInitBegin, E = ExternalOptionsInitEnd; I != E; ++I)
      (*I)();
  }

The relevant code for other platforms is in `compiler-rt/lib/profile/InstrProfilingPlatform*.c`.

If we did this, we'd maybe want to control it with a CMake configuration? When off (always for platforms where we don't have/know the magic incantations), the various `initOptions()` would be added to static initializers as before. When on, we could add `-Werror=global-constructors` to other libraries (once they're clean).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105959/new/

https://reviews.llvm.org/D105959



More information about the cfe-commits mailing list