Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Opt] Enable statically-linked plugin support #79227

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

wsmoses
Copy link
Member

@wsmoses wsmoses commented Jan 23, 2024

Companion PR to #70171 except now for opt rather than clang.

This PR enables using custom passes in plugins, when statically linked against opt.

See #79205 for a standalone bazel PR needed for this to be used in a different build system.

@efriedma-quic
Copy link
Collaborator

Let me see if I understand your constraints correctly:

  • You want to add a plugin to an "unmodified" opt tool.
  • "Unmodified" means you can't modify any source files or build settings.
  • This is currently impossible: we don't install the relevant object files, so there's no way to refer to them. But [CMake/Bazel] Support usage of opt driver as a library #79205 hacks the build config to install the relevant object files as a library, so you can build your own binary.

If making the "opt" tool a library is actually helpful, I guess I'm not really against it... but please add a proper entry-point instead of abusing dlsym().

@wsmoses
Copy link
Member Author

wsmoses commented Jan 24, 2024

What would you propose in the alternate? I can only otherwise think of adding a global variable, like in the earliest revisions of #70171 .

@efriedma-quic
Copy link
Collaborator

Rename main() to OptDriverMain(), add a new file opt-executable.cpp that's a wrapper around it. Add whatever parameters you need to OptDriverMain().

Alternatively, adding a global variable to opt.cpp isn't that terrible. We want to avoid global variables in core libraries so we don't have issues with shared state, but I wouldn't expect opt-driver to be used in that sort of context.

Copy link

github-actions bot commented Jan 24, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@wsmoses
Copy link
Member Author

wsmoses commented Jan 25, 2024

@efriedma-quic this now does the new file with wrapper, with tests, as discussed. Mind reviewing?

@wsmoses wsmoses requested a review from nico January 25, 2024 02:08
@aeubanks
Copy link
Contributor

if this is just to be used in non-core tools, I'd prefer a llvm::Registry approach (basically the global variable approach @efriedma-quic mentioned), like how clang extensions work (e.g. here). then around here we can invoke all of those

that seems much simpler than this PR + #79205

@efriedma-quic
Copy link
Collaborator

that seems much simpler than this PR + #79205

I'm not sure I understand what you're getting at with the reference to #79205 . Most of the decisions there were constrained by producing something that actually builds correctly in all configurations. The goal is to allow users to build an "opt-with-a-plugin" without rebuilding LLVM. So we put the logic of opt into a library. We have to be able to build that library as a shared library for -DBUILD_SHARED_LIBS builds, so that library can't contain the definition of main(). So in sum, we need to have a library that contains all the logic, and exposes optMain() to call that logic.

We could remove the parameter from optMain, and use a global variable instead, but that doesn't really simplify anything.

@aeubanks
Copy link
Contributor

I vaguely remember the end result of the clang patch being that internally we cloned the build target for clang but with an extra dependency on a file that registered a clang plugin via a static constructor. If we did the same thing here, we wouldn't need these patches. I may be misremembering though. @wsmoses am I misunderstanding?

@efriedma-quic
Copy link
Collaborator

The clang version of this only supported Bazel builds, not CMake builds, so it didn't have to worry about -DBUILD_SHARED_LIBS. (I didn't realize this at the time because the patch didn't actually touch those bits.)

@wsmoses
Copy link
Member Author

wsmoses commented Jan 27, 2024

So the way the clang one worked, was as follows:

Bazel's build for clang already separated all of the clang driver libraries into a separate clang-driver library (

) which then to build clang in Bazel one just makes an executable with it ( ).

For our custom clang, we simply linked the clang-driver against whatever plugin we wanted.

Doing the same for opt has two issues:

  1. There is no opt-driver like library (instead the bazel executable contains all of the functionality).
  2. Opt plugins are only loaded by passing in a path to a .so to load, and do not have an alternate registration mechanism (e.g. registry, list of args, other global, etc).

Originally the first Bazel PR (#79205) was a 2-line bazel patch which added a similar opt-driver library target in Bazel, like there exists already for clang. Code review requested that if this was going to happen, one should also make a library for the opt driver in CMake as well.

Unfortunately making such a library in CMake is a non-trivial task, if one wants to permit all build targets (e.g. shared libs, etc), which obviously we need to support. Specifically, it required creating a separate opt.cpp file which just contains main, as distinct from the actual opt functionality. This was required to make shared library linkage work (among other minor things, like not linking the new lib into libLLVM, etc).

Since the goal was to support additional plugins, we went ahead and just added the vector of callbacks to the optMain function in the new library.

We could also support a registry, and remove the vector of callbacks to optMain. However, the need for the separate opt.cpp with just main for each executable variant [e.g. actual opt, this test plugin opt], is required for CMake + build variants.

In light of that I'd say the two most reasonable design decisions are to either:

  1. pass the plugins as a vector to optMain, since we already have to have an optMain for the cmake library
  2. add a registry, but remove support for CMake and only allow it for Bazel.

--

  1. is nice because all LLVM users can do something like this. Also incidentally this is somewhat similar to how this works for mlir with mlirOptMain (
    LogicalResult mlir::MlirOptMain(llvm::raw_ostream &outputStream,
    ). However, this is different from clang, and each downstream user needs to have their own clang
  2. is code-wise simpler, but only works for Bazel.

Copy link
Contributor

@aeubanks aeubanks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the explanation

I took a look at the llvm driver code and it seems pretty similar to this, so I'm ok with this now

perhaps this might conflict with the llvm driver stuff if we ever decide to add opt to it, but we can cross that bridge when we get there (e.g. expose a global variable in opt-driver)

; REQUIRES: x86-registered-target
; RUN: opt-printplugin %s -passes="printpass" -disable-output 2>&1 | FileCheck %s

; REQUIRES: plugins
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this actually requires plugins, that's only necessary for shared library plugins IIUC

@@ -0,0 +1,8 @@
add_llvm_tool(opt-printplugin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this add_llvm_example? then test will need REQUIRES: examples

STATIC
NewPMDriver.cpp
optdriver.cpp
PARTIAL_SOURCES_INTENDED
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need PARTIAL_SOURCES_INTENDED anymore

SUPPORT_PLUGINS
)
target_link_libraries(opt-printplugin PRIVATE LLVMOptDriver)
export_executable_symbols_for_plugins(opt-printplugin)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this for an example/test binary?

@@ -0,0 +1,67 @@
//===- opt-printplugin.cpp - The LLVM Modular Optimizer
//-------------------------------===//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting


} // namespace

extern "C" int optMain(int argc, char **argv,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optMain() shouldn't be extern "C" since it uses C++ classes. this mirrors the llvm driver support, e.g. llvm/cmake/modules/llvm-driver-template.cpp.in

@@ -0,0 +1,9 @@
# We don't want to link this into libLLVM
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my understanding, how do we tell the build system not to link this into libLLVM?

target_link_libraries(opt PRIVATE LLVMOptDriver)

export_executable_symbols_for_plugins(opt)
add_subdirectory(lib)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(can't comment above due to github limitations) should LLVM_LINK_COMPONENTS go down to llvm/tools/opt/lib/CMakeLists.txt?

"specified (JSON) file (should be abs path as we use"
" append mode to insert new JSON objects)"),
cl::value_desc("filename"), cl::init(""));
cl::opt<std::string> VerifyDIPreserveExport(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you commit the formatting changes ahead of time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants