Skip to content

recognizing ENZYME_RUNPASS for lib/LLVM Enzyme builds #2245

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

Merged
merged 9 commits into from
Feb 21, 2025
Merged

Conversation

ZuseZ4
Copy link
Collaborator

@ZuseZ4 ZuseZ4 commented Feb 15, 2025

I noticed that the ENZYME_RUNPASS variable is ignored, when you just pass it as -DENZYME_RUNPASS to cmake.
This might also affect your BUILD file, idk.
With these changes it now does run the augmentedPassBuilder.

@ZuseZ4 ZuseZ4 requested a review from wsmoses February 15, 2025 04:16
Copy link
Member

@wsmoses wsmoses left a comment

Choose a reason for hiding this comment

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

This should be disabled for llvmenzyme thougj? The flag says that the enzyme pass should be injected to be run by default in the pass pipeline

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

What is the difference between libEnzyme-X.so and LLVMEnzyme-19.so? I thought they would have just different linking behaviour, but the same functionality? We use libEnzyme because it fixed some linking issues I can't remember, so I don't mind only updating it and removing the LLVMEnzyme one (?)

@wsmoses
Copy link
Member

wsmoses commented Feb 15, 2025

LLVMEnzyme is an llvm pass plugin, libenzyme is a dynamic library you can link into programs that aren't llvm's opt

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

Fair, I vaguely had in mind that at some point I also linked against LLVMEnzyme when using the Enzyme API, but I might have confused something.

Also, remember you'll need to merge, and can't just approve things.

@ZuseZ4 ZuseZ4 enabled auto-merge February 15, 2025 04:26
@ZuseZ4 ZuseZ4 requested a review from wsmoses February 15, 2025 14:17
Copy link
Member

@wsmoses wsmoses left a comment

Choose a reason for hiding this comment

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

I'm still not understanding why this is needed here

@wsmoses wsmoses disabled auto-merge February 15, 2025 14:19
@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

I want Enzymes opt pass to run befire autodiff, as it is supposed to improve performance. Right now Rust already sets -DENZYME_RUNPASS when calling cmake, but the value is ignored and does not cause Enzyme to run the optimization pass. It only affects libEnzyme, as lld and clangenzyme have it hardcoded. I could also hardcode it for libEnzyme, but this solution allows other users to run the autodiff pass without the opt pass.

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

#ifdef ENZYME_RUNPASS

@wsmoses
Copy link
Member

wsmoses commented Feb 15, 2025

Why not just run augmentPassBuilder?

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

Why have RustEnxyme differ from ClangEnzyme or LLDEnzyem?

@wsmoses
Copy link
Member

wsmoses commented Feb 15, 2025

The use you linked is specific to llvm pass loading which doesn't make sense for API users, since its better form to build the pass manager directly (like with the function I mentioned)

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

This has been discussed e.g. here. There I had asked which functions I should use in which order. I ended up staring with another llvm dev at the enzyme code and this is what we came up with.

From what we saw, we will always run augmentPassBuilder and then registerEnzyme to then run the enzyme pass.
We will never just run augmentPassBuilder or the enzyme pass without the other. So if there is a performance benefit to run augmentPassBuilder separately, it would be good if you could give an explanation on how it's supposed to be used and what is the difference over just enabling it here. Because based on your explanation I would just run

augmentPassBuilder(PB);
registerEnzyme(PB); // With the augmentPassBuilder configured out
    if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) {
      std::string ErrMsg = toString(std::move(Err));
      LLVMRustSetLastError(ErrMsg.c_str());
      return LLVMRustResult::Failure;
    }

I don't see how exposing and ffi-wrapping agumentPassBuilder is an improvement over the code I merged after the zulip discussions with other devs which assumes the augmentPassBuilder to implicitly run (which I try to fix here since it doesn't, because cmake dropps the ENZYME_RUNPASS flag for non-Clang/LLD builds):
https://github.com/rust-lang/rust/pull/136419/files#diff-eac3d5ef63f39b7914ae9015f31b8d87353ea8fbcd5b02a7335dd86c557e7625

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 15, 2025

Ok, wild guess now, but in an attempt to understand the difference, could it be that you missed the messages/pings where I/Rust people asked about the Enzyme pass?
Rust moved over to a pass-based Enzyme approach around October last year, based on your recommendation in some DMs, hence all my question about the enzyme pass since.
If you missed all of those this discussion suddenly makes a lot more sense to me and hopefully now to you.

@ZuseZ4 ZuseZ4 requested a review from wsmoses February 15, 2025 19:31
@wsmoses
Copy link
Member

wsmoses commented Feb 15, 2025

I'm still a bit confused how you're intending to use this. In any case, perhaps you can make a second function void augmentAndRegisterEnzyme(PB, bool shouldAugment) which contains the current definition, and then is true if the current Enzyme_runpass is set. That way you can just call the api function without setting a compile time var

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 16, 2025

The intention is to have Rust differ as little as possible from Clang/LLD-Enzyme to ease maintenance, since all three are pass based, as opposed to Julia which is Api based., Clang/LLD Enzyme both define this variable to first run augmentPassBuilder and then register Enzyme and run it. So my confusion comes from your recommendation to handle Rust and C++ different here.
Doing it at runtime would be totally fine for me, but then I wonder why you don't do the same with the clang/lld plugin? What are you confused about?

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 16, 2025

Also for the long term goal, the idea is to have autodiff run as the pass (e.g. because of your recommendation and because it handles higher order derivatives in the right order automatically). For things like custom-derivatives you recommended to not copy c++Enzyme, but rather link against libEnzyme, so we can use the more advanced registerCustomDerivative functions, since they are more granular than the metadata approach.

So my understanding is that clang will in the future move to the api for custom derivatices, Enzyme.jl will move to the pass for autodiff (but keep using the api for things like custom derivatives) and then all 3 frontends will behave identical. Since Rust is coming in later, I directly try to do the right approach for each feature. Does that help?

@ZuseZ4
Copy link
Collaborator Author

ZuseZ4 commented Feb 17, 2025

@wsmoses adding the runtime variant and updated the old one to forward, to make sure they can never get out of sync.

@ZuseZ4 ZuseZ4 requested a review from wsmoses February 19, 2025 07:25
@wsmoses wsmoses merged commit b781d84 into main Feb 21, 2025
16 of 23 checks passed
@ZuseZ4 ZuseZ4 deleted the enzyme-runpass branch February 21, 2025 02:01
gbaraldi pushed a commit to gbaraldi/Enzyme that referenced this pull request Jun 27, 2025
* Fix non data type

* fix

* Update compiler.jl
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.

2 participants