Best approach to replace a built-in pass with an out-of-tree implementation

Hi everyone,

I am planning to start working on a custom IR transformation pass that will serve as a specialized alternative to an existing built-in LLVM pass.

My goal is to develop this as an out-of-tree project, but I would like to find a clean way to “replace” the original pass with my implementation during the pipeline execution, without having to maintain a fork of the LLVM core source.

While I am aware that individual passes can often be disabled via command-line flags (e.g., -disable-X), I am looking for a more robust and programmatic way to handle this replacement within a plugin or a custom driver.

Additionally, I’d like to keep the existing unit tests and regression tests from the llvm-project unchanged, but have them run against my custom implementation to verify correctness and performance.

Regarding the New Pass Manager, I have a few specific questions:

  1. Disabling Built-in Passes: Is there a standard mechanism to prevent a specific default pass from running within the PassBuilder pipelines?

  2. Substitution via Callbacks: Can I use PassBuilder callbacks to intercept the pipeline construction and swap a built-in pass with my out-of-tree version? Eventually, is it generally preferred to provide a custom PipelineElement parser or to hook into the OptimizerLastEP?

  3. Command Line Integration: If I load my pass as a plugin via -load-pass-plugin, is it possible to “shadow” the existing pass name, or should I use a unique name and manually adjust the optimization level pipelines?

I am trying to understand if LLVM provides a “hook” for this kind of substitution or if I should expect to manually reconstruct part of the pipeline.

Thanks for any insights or suggestions!