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

Autodiff Upstreaming - rustc_codegen_llvm changes #130060

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ZuseZ4
Copy link
Contributor

@ZuseZ4 ZuseZ4 commented Sep 7, 2024

Now that the autodiff/Enzyme backend is merged, this is an upstream PR for the rustc_codegen_llvm changes.
It also includes small changes to three files under compiler/rustc_ast, which overlap with my frontend PR (#129458).
Here I only include minimal definitions of structs and enums to be able to build this backend code.
The same goes for minimal changes to compiler/rustc_codegen_ssa, the majority of changes there will be in another PR, once either this or the frontend gets merged.

We currently have 68 files left to merge, 19 in the frontend PR, 21 (+3 from the frontend) in this PR, and then ~30 in the middle-end.

This PR is large because it includes two of my three large files (~800 loc each). I could also first only upstream enzyme_ffi.rs, but I think people might want to see some use of these bindings in the same PR?

To already highlight the things which reviewers might want to discuss:

  1. enzyme_ffi.rs: I do have a fallback module to make sure that we don't link rustc against Enzyme when we build rustc without autodiff support.

  2. add_panic_msg_to_global was a pain to write and I currently can't even use it. Enzyme writes gradients into shadow memory. Pass in one float scalar? We'll allocate and return an extra float telling you how this float affected the output. Pass in a slice of floats? We'll let you allocate the vector and pass in a mutable reference to a float slice, we'll then write the gradient into that slice. It should be at least as large as your original slice, so we check that and panic if not. Currently we panic silently, but I already generate a nicer panic message with this function. I just don't know how to print it to the user. yet. I discussed this with a few rustc devs and the best we could come up with (for now), was to look for mangled panic calls in the IR and pick one, which works surprisingly reliably. If someone knows a good way to clean this up and print the panic message I'm all in, otherwise I can remove the code that writes the nicer panic message and keep the silent panic, since it's enough for soundness. Especially since this PR is already a bit larger.

  3. SanitizeHWAddress: When differentiating C++, Enzyme can use TBAA to "understand" enums/unions, but for Rust we don't have this information. LLVM might to speculative loads which (without TBAA) confuse Enzyme, so we disable those with this attribute. This attribute is only set during the first opt run before Enzyme differentiates code. We then remove it again once we are done with autodiff and run the opt pipeline a second time. Since enums are everywhere in Rust, support for them is crucial, but if this looks too cursed I can remove these ~100 lines and keep them in my fork for now, we can then discuss them separately to make this PR simpler?

  4. Duplicated llvm-opt runs: Differentiating already optimized code (and being able to do additional optimizations on the fly, e.g. for GPU code) is the reason why Enzyme is so fast, so the compile time is acceptable for autodiff users: https://enzyme.mit.edu/talks/Publications/ (There are also algorithmic issues in Enzyme core which are more serious than running opt twice).

  5. I assume that if we merge these minimal cg_ssa changes here already, I also need to fix the other backends (GCC and cliff) to have dummy implementations, correct?

  6. I'm happy to split this PR up further if reviewers have recommendations on how to.

For the full implementation, see: #129175

Tracking:

@rustbot
Copy link
Collaborator

rustbot commented Sep 7, 2024

r? @fee1-dead

rustbot has assigned @fee1-dead.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot
Copy link
Collaborator

rustbot commented Sep 7, 2024

⚠️ Warning ⚠️

  • These commits modify submodules.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 7, 2024
@rustbot
Copy link
Collaborator

rustbot commented Sep 7, 2024

This PR modifies config.example.toml.

If appropriate, please update CONFIG_CHANGE_HISTORY in src/bootstrap/src/utils/change_tracker.rs.

Some changes occurred in cfg and check-cfg configuration

cc @Urgau

@rust-log-analyzer

This comment has been minimized.

@@ -176,6 +176,8 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
// NOTE: These insertions should be kept in sync with
// `CheckCfg::fill_well_known` below.

ins_none!(sym::autodiff_fallback);
Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't be insta stable, it should be at least gated behind nightly compiler.

Suggested change
ins_none!(sym::autodiff_fallback);
if sess.is_nightly_build() {
ins_none!(sym::autodiff_fallback);
}

Please also follow all the steps regarding a new cfg as defined in the top of this file (as well as the tests files):

//! ## Adding a new cfg
//!
//! Adding a new feature requires two new symbols one for the cfg it-self
//! and the second one for the unstable feature gate, those are defined in
//! `rustc_span::symbol`.
//!
//! As well as the following points,
//! - Add the activation logic in [`default_configuration`]
//! - Add the cfg to [`CheckCfg::fill_well_known`] (and related files),
//! so that the compiler can know the cfg is expected
//! - Add the cfg in [`disallow_cfgs`] to disallow users from setting it via `--cfg`
//! - Add the feature gating in `compiler/rustc_feature/src/builtin_attrs.rs`

@jieyouxu jieyouxu added the F-autodiff `#![feature(autodiff)]` label Sep 7, 2024
@fee1-dead
Copy link
Member

r? compiler

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Oct 4, 2024

☔ The latest upstream changes (presumably #131237) made this pull request unmergeable. Please resolve the merge conflicts.

@michaelwoerister
Copy link
Member

r? compiler

@rustbot rustbot assigned davidtwco and unassigned michaelwoerister Oct 7, 2024
@davidtwco
Copy link
Member

There's very little chance of this being merged in one PR with one commit of this size. You'll need to split this up into well-commented/motivated PRs that can be landed one at a time. I haven't spent much time looking at this PR, so I don't have any suggestions on how to split this up. I'd recommend finding someone on the compiler team who is interested in these changes and who you can work with to do the reviews.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

I don't have time to review this, so just one drive-by note: It looks like a decent part of the extra FFI APIs in enzyme_ffi.rs are essentially duplicates of things that we already have bindings for under slightly different names and signatures. Like we already have LLVMRustAddFunctionAttributes/LLVMRustAddCallSiteAttributes and this introduces LLVMRustAddEnumAttributeAtIndex. It also looks like the code doesn't make use of the Builder abstraction and instead calls FFI APIs directly everywhere, which is probably also where the duplication comes from.

@davidtwco davidtwco added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 11, 2024
@alex-semenyuk alex-semenyuk added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 13, 2024
@ZuseZ4 ZuseZ4 force-pushed the enzyme-cg-llvm branch 2 times, most recently from a170908 to 11c3bae Compare November 21, 2024 00:53
@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-18 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
#16 exporting to docker image format
#16 sending tarball 28.0s done
#16 DONE 42.2s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-18]
debug: `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` configured.
---
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-18', '--enable-llvm-link-shared', '--set', 'rust.randomize-layout=true', '--set', 'rust.thin-lto-import-instr-limit=10', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--set', 'rust.lld=false', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-18/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.randomize-layout := True
configure: rust.thin-lto-import-instr-limit := 10
---

warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:408:52: error: ‘LLVMRustAttribute’ has not been declared
warning: rustc_llvm@0.0.0:   408 |                                                    LLVMRustAttribute RustAttr) {
warning: rustc_llvm@0.0.0:       |                                                    ^~~~~~~~~~~~~~~~~
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp: In function ‘void LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef, size_t, int)’:
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:409:53: error: invalid conversion from ‘int’ to ‘LLVMAtomicOrdering’ [-fpermissive]
warning: rustc_llvm@0.0.0:   409 |   LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
warning: rustc_llvm@0.0.0:       |                                                     |
warning: rustc_llvm@0.0.0:       |                                                     int
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:58:51: note:   initializing argument 1 of ‘llvm::AtomicOrdering fromRust(LLVMAtomicOrdering)’
warning: rustc_llvm@0.0.0:    58 | static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
warning: rustc_llvm@0.0.0:    58 | static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
warning: rustc_llvm@0.0.0:       |                                ~~~~~~~~~~~~~~~~~~~^~~~~~~~
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:409:52: error: cannot convert ‘llvm::AtomicOrdering’ to ‘unsigned int’
warning: rustc_llvm@0.0.0:   409 |   LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
warning: rustc_llvm@0.0.0:       |                                                    |
warning: rustc_llvm@0.0.0:       |                                                    llvm::AtomicOrdering
warning: rustc_llvm@0.0.0: In file included from llvm-wrapper/RustWrapper.cpp:3:
warning: rustc_llvm@0.0.0: In file included from llvm-wrapper/RustWrapper.cpp:3:
warning: rustc_llvm@0.0.0: /usr/lib/llvm-18/include/llvm-c/Core.h:2729:46: note:   initializing argument 3 of ‘void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef, LLVMAttributeIndex, unsigned int)’
warning: rustc_llvm@0.0.0:  2729 |                                     unsigned KindID);
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp: At global scope:
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:419:49: error: ‘LLVMRustAttribute’ has not been declared
warning: rustc_llvm@0.0.0:   419 |                                                 LLVMRustAttribute RustAttr) {
warning: rustc_llvm@0.0.0:       |                                                 ^~~~~~~~~~~~~~~~~
warning: rustc_llvm@0.0.0:       |                                                 ^~~~~~~~~~~~~~~~~
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp: In function ‘void LLVMRustAddEnumAttributeAtIndex(LLVMContextRef, LLVMValueRef, size_t, int)’:
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:420:66: error: cannot convert ‘int’ to ‘LLVMRustAttributeKind’
warning: rustc_llvm@0.0.0:   420 |   LLVMAddAttributeAtIndex(F, index, LLVMRustCreateAttrNoValue(C, RustAttr));
warning: rustc_llvm@0.0.0:       |                                                                  |
warning: rustc_llvm@0.0.0:       |                                                                  int
warning: rustc_llvm@0.0.0:       |                                                                  int
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:413:67: note:   initializing argument 2 of ‘LLVMOpaqueAttributeRef* LLVMRustCreateAttrNoValue(LLVMContextRef, LLVMRustAttributeKind)’
warning: rustc_llvm@0.0.0:   413 | LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp: At global scope:
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:425:33: error: ‘LLVMRustAttribute’ has not been declared
warning: rustc_llvm@0.0.0:   425 |                                 LLVMRustAttribute RustAttr) {
warning: rustc_llvm@0.0.0:       |                                 ^~~~~~~~~~~~~~~~~
warning: rustc_llvm@0.0.0:       |                                 ^~~~~~~~~~~~~~~~~
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp: In function ‘LLVMOpaqueAttributeRef* LLVMRustGetEnumAttributeAtIndex(LLVMValueRef, size_t, int)’:
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:426:57: error: invalid conversion from ‘int’ to ‘LLVMAtomicOrdering’ [-fpermissive]
warning: rustc_llvm@0.0.0:   426 |   return LLVMGetEnumAttributeAtIndex(F, index, fromRust(RustAttr));
warning: rustc_llvm@0.0.0:       |                                                         |
warning: rustc_llvm@0.0.0:       |                                                         int
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:58:51: note:   initializing argument 1 of ‘llvm::AtomicOrdering fromRust(LLVMAtomicOrdering)’
warning: rustc_llvm@0.0.0:    58 | static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
warning: rustc_llvm@0.0.0:    58 | static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
warning: rustc_llvm@0.0.0:       |                                ~~~~~~~~~~~~~~~~~~~^~~~~~~~
warning: rustc_llvm@0.0.0: llvm-wrapper/RustWrapper.cpp:426:56: error: cannot convert ‘llvm::AtomicOrdering’ to ‘unsigned int’
warning: rustc_llvm@0.0.0:   426 |   return LLVMGetEnumAttributeAtIndex(F, index, fromRust(RustAttr));
warning: rustc_llvm@0.0.0:       |                                                        |
warning: rustc_llvm@0.0.0:       |                                                        llvm::AtomicOrdering
warning: rustc_llvm@0.0.0:       |                                                        llvm::AtomicOrdering
warning: rustc_llvm@0.0.0: /usr/lib/llvm-18/include/llvm-c/Core.h:2724:55: note:   initializing argument 3 of ‘LLVMOpaqueAttributeRef* LLVMGetEnumAttributeAtIndex(LLVMValueRef, LLVMAttributeIndex, unsigned int)’
warning: rustc_llvm@0.0.0:  2724 |                                              unsigned KindID);

error: failed to run custom build command for `rustc_llvm v0.0.0 (/checkout/compiler/rustc_llvm)`

Caused by:
Caused by:
  process didn't exit successfully: `/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/release/build/rustc_llvm-41c1e748df723216/build-script-build` (exit status: 1)
  --- stdout
  cargo:rustc-check-cfg=cfg(llvm_component,values("ipo"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("bitreader"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("bitwriter"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("linker"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("asmparser"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("lto"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("coverage"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("instrumentation"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("x86"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("arm"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("aarch64"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("amdgpu"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("avr"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("loongarch"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("m68k"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("csky"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("mips"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("powerpc"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("systemz"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("jsbackend"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("webassembly"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("msp430"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("sparc"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("nvptx"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("hexagon"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("riscv"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("xtensa"))
  cargo:rustc-check-cfg=cfg(llvm_component,values("bpf"))
  cargo:rerun-if-env-changed=RUST_CHECK
  cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR
  cargo:rerun-if-env-changed=REAL_LIBRARY_PATH
  cargo:rerun-if-env-changed=LLVM_CONFIG
  cargo:rerun-if-changed=/usr/lib/llvm-18/bin/llvm-config
  cargo:rustc-cfg=llvm_component="aarch64"
  cargo:rustc-cfg=llvm_component="amdgpu"
  cargo:rustc-cfg=llvm_component="arm"
  cargo:rustc-cfg=llvm_component="asmparser"
  cargo:rustc-cfg=llvm_component="avr"
  cargo:rustc-cfg=llvm_component="bitreader"
  cargo:rustc-cfg=llvm_component="bitwriter"
  cargo:rustc-cfg=llvm_component="bpf"
  cargo:rustc-cfg=llvm_component="coverage"
  cargo:rustc-cfg=llvm_component="hexagon"
  cargo:rustc-cfg=llvm_component="instrumentation"
  cargo:rustc-cfg=llvm_component="ipo"
  cargo:rustc-cfg=llvm_component="linker"
  cargo:rustc-cfg=llvm_component="loongarch"
  cargo:rustc-cfg=llvm_component="lto"
  cargo:rustc-cfg=llvm_component="m68k"
  cargo:rustc-cfg=llvm_component="mips"
  cargo:rustc-cfg=llvm_component="msp430"
  cargo:rustc-cfg=llvm_component="nvptx"
  cargo:rustc-cfg=llvm_component="powerpc"
  cargo:rustc-cfg=llvm_component="riscv"
  cargo:rustc-cfg=llvm_component="sparc"
  cargo:rustc-cfg=llvm_component="systemz"
  cargo:rustc-cfg=llvm_component="webassembly"
  cargo:rustc-cfg=llvm_component="x86"
  cargo:rustc-cfg=llvm_component="xtensa"
  cargo:rerun-if-env-changed=LLVM_RUSTLLVM
  cargo:rerun-if-env-changed=LLVM_ASSERTIONS
  cargo:rerun-if-changed=llvm-wrapper/README
  cargo:rerun-if-changed=llvm-wrapper/Linker.cpp
  cargo:rerun-if-changed=llvm-wrapper/CoverageMappingWrapper.cpp
  cargo:rerun-if-changed=llvm-wrapper/PassWrapper.cpp
  cargo:rerun-if-changed=llvm-wrapper/SuppressLLVMWarnings.h
  cargo:rerun-if-changed=llvm-wrapper/ArchiveWrapper.cpp
  cargo:rerun-if-changed=llvm-wrapper/LLVMWrapper.h
  cargo:rerun-if-changed=llvm-wrapper/SymbolWrapper.cpp
  cargo:rerun-if-changed=llvm-wrapper/RustWrapper.cpp
  cargo:rerun-if-changed=llvm-wrapper/.editorconfig
  OUT_DIR = Some(/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/build/rustc_llvm-f80b4469d65e5503/out)
  TARGET = Some(x86_64-unknown-linux-gnu)
  HOST = Some(x86_64-unknown-linux-gnu)
  cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
  CXX_x86_64-unknown-linux-gnu = None
  CXX_x86_64-unknown-linux-gnu = None
  cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
  CXX_x86_64_unknown_linux_gnu = Some(sccache c++)
  cargo:rerun-if-env-changed=CC_KNOWN_WRAPPER_CUSTOM
  CC_KNOWN_WRAPPER_CUSTOM = None
  cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
  CRATE_CC_NO_DEFAULTS = None
  DEBUG = Some(false)
  DEBUG = Some(false)
  CARGO_CFG_TARGET_FEATURE = Some(fxsr,sse,sse2)
  CXXFLAGS_x86_64-unknown-linux-gnu = None
  cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
  cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
  CXXFLAGS_x86_64_unknown_linux_gnu = Some(-ffunction-sections -fdata-sections -fPIC -m64)
  cargo:rerun-if-env-changed=CC_SHELL_ESCAPED_FLAGS
  CC_SHELL_ESCAPED_FLAGS = None
  cargo:warning=llvm-wrapper/RustWrapper.cpp:408:52: error: ‘LLVMRustAttribute’ has not been declared
  cargo:warning=  408 |                                                    LLVMRustAttribute RustAttr) {
  cargo:warning=      |                                                    ^~~~~~~~~~~~~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp: In function ‘void LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef, size_t, int)’:
  cargo:warning=llvm-wrapper/RustWrapper.cpp:409:53: error: invalid conversion from ‘int’ to ‘LLVMAtomicOrdering’ [-fpermissive]
  cargo:warning=  409 |   LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
  cargo:warning=      |                                                     ^~~~~~~~
  cargo:warning=      |                                                     |
  cargo:warning=      |                                                     int
  cargo:warning=llvm-wrapper/RustWrapper.cpp:58:51: note:   initializing argument 1 of ‘llvm::AtomicOrdering fromRust(LLVMAtomicOrdering)’
  cargo:warning=   58 | static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
  cargo:warning=      |                                ~~~~~~~~~~~~~~~~~~~^~~~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp:409:52: error: cannot convert ‘llvm::AtomicOrdering’ to ‘unsigned int’
  cargo:warning=  409 |   LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
  cargo:warning=      |                                            ~~~~~~~~^~~~~~~~~~
  cargo:warning=      |                                                    |
  cargo:warning=      |                                                    llvm::AtomicOrdering
  cargo:warning=In file included from llvm-wrapper/RustWrapper.cpp:3:
  cargo:warning=/usr/lib/llvm-18/include/llvm-c/Core.h:2729:46: note:   initializing argument 3 of ‘void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef, LLVMAttributeIndex, unsigned int)’
  cargo:warning= 2729 |                                     unsigned KindID);
  cargo:warning=      |                                     ~~~~~~~~~^~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp: At global scope:
  cargo:warning=llvm-wrapper/RustWrapper.cpp:419:49: error: ‘LLVMRustAttribute’ has not been declared
  cargo:warning=  419 |                                                 LLVMRustAttribute RustAttr) {
  cargo:warning=      |                                                 ^~~~~~~~~~~~~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp: In function ‘void LLVMRustAddEnumAttributeAtIndex(LLVMContextRef, LLVMValueRef, size_t, int)’:
  cargo:warning=llvm-wrapper/RustWrapper.cpp:420:66: error: cannot convert ‘int’ to ‘LLVMRustAttributeKind’
  cargo:warning=  420 |   LLVMAddAttributeAtIndex(F, index, LLVMRustCreateAttrNoValue(C, RustAttr));
  cargo:warning=      |                                                                  ^~~~~~~~
  cargo:warning=      |                                                                  |
  cargo:warning=      |                                                                  int
  cargo:warning=llvm-wrapper/RustWrapper.cpp:413:67: note:   initializing argument 2 of ‘LLVMOpaqueAttributeRef* LLVMRustCreateAttrNoValue(LLVMContextRef, LLVMRustAttributeKind)’
  cargo:warning=  413 | LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
  cargo:warning=      |                                             ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp: At global scope:
  cargo:warning=llvm-wrapper/RustWrapper.cpp:425:33: error: ‘LLVMRustAttribute’ has not been declared
  cargo:warning=  425 |                                 LLVMRustAttribute RustAttr) {
  cargo:warning=      |                                 ^~~~~~~~~~~~~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp: In function ‘LLVMOpaqueAttributeRef* LLVMRustGetEnumAttributeAtIndex(LLVMValueRef, size_t, int)’:
  cargo:warning=llvm-wrapper/RustWrapper.cpp:426:57: error: invalid conversion from ‘int’ to ‘LLVMAtomicOrdering’ [-fpermissive]
  cargo:warning=  426 |   return LLVMGetEnumAttributeAtIndex(F, index, fromRust(RustAttr));
  cargo:warning=      |                                                         ^~~~~~~~
  cargo:warning=      |                                                         |
  cargo:warning=      |                                                         int
  cargo:warning=llvm-wrapper/RustWrapper.cpp:58:51: note:   initializing argument 1 of ‘llvm::AtomicOrdering fromRust(LLVMAtomicOrdering)’
  cargo:warning=   58 | static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
  cargo:warning=      |                                ~~~~~~~~~~~~~~~~~~~^~~~~~~~
  cargo:warning=llvm-wrapper/RustWrapper.cpp:426:56: error: cannot convert ‘llvm::AtomicOrdering’ to ‘unsigned int’
  cargo:warning=  426 |   return LLVMGetEnumAttributeAtIndex(F, index, fromRust(RustAttr));
  cargo:warning=      |                                                ~~~~~~~~^~~~~~~~~~
  cargo:warning=      |                                                        |
  cargo:warning=      |                                                        llvm::AtomicOrdering
  cargo:warning=/usr/lib/llvm-18/include/llvm-c/Core.h:2724:55: note:   initializing argument 3 of ‘LLVMOpaqueAttributeRef* LLVMGetEnumAttributeAtIndex(LLVMValueRef, LLVMAttributeIndex, unsigned int)’
  cargo:warning= 2724 |                                              unsigned KindID);
  cargo:warning=      |                                              ~~~~~~~~~^~~~~~
  --- stderr



  error occurred: Command "sccache" "c++" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-I/usr/lib/llvm-18/include" "-std=c++17" "-fno-exceptions" "-funwind-tables" "-D_GNU_SOURCE" "-D__STDC_CONSTANT_MACROS" "-D__STDC_FORMAT_MACROS" "-D__STDC_LIMIT_MACROS" "-DLLVM_COMPONENT_AARCH64" "-DLLVM_COMPONENT_AMDGPU" "-DLLVM_COMPONENT_ARM" "-DLLVM_COMPONENT_ASMPARSER" "-DLLVM_COMPONENT_AVR" "-DLLVM_COMPONENT_BITREADER" "-DLLVM_COMPONENT_BITWRITER" "-DLLVM_COMPONENT_BPF" "-DLLVM_COMPONENT_COVERAGE" "-DLLVM_COMPONENT_HEXAGON" "-DLLVM_COMPONENT_INSTRUMENTATION" "-DLLVM_COMPONENT_IPO" "-DLLVM_COMPONENT_LINKER" "-DLLVM_COMPONENT_LOONGARCH" "-DLLVM_COMPONENT_LTO" "-DLLVM_COMPONENT_M68K" "-DLLVM_COMPONENT_MIPS" "-DLLVM_COMPONENT_MSP430" "-DLLVM_COMPONENT_NVPTX" "-DLLVM_COMPONENT_POWERPC" "-DLLVM_COMPONENT_RISCV" "-DLLVM_COMPONENT_SPARC" "-DLLVM_COMPONENT_SYSTEMZ" "-DLLVM_COMPONENT_WEBASSEMBLY" "-DLLVM_COMPONENT_X86" "-DLLVM_COMPONENT_XTENSA" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/build/rustc_llvm-f80b4469d65e5503/out/7372e21ddc8be4fd-RustWrapper.o" "-c" "llvm-wrapper/RustWrapper.cpp" with args c++ did not execute successfully (status code exit status: 1).

warning: build failed, waiting for other jobs to finish...
Build completed unsuccessfully in 0:01:02
  local time: Thu Nov 21 01:25:03 UTC 2024

@ZuseZ4
Copy link
Contributor Author

ZuseZ4 commented Nov 21, 2024

Ok, I reimplemented autodiff using a different approach and dropped safety checks as well as some perf optimizations. That brought the size down from 2.5k for the previous master to 1.1k here: EnzymeAD#186

This PR here still just contains changes to rustc_codegen_llvm, as well as a minimal set of additional ones that are needed to make it compile.
The 200 loc in back/write.rs are only executed if rustc is build with enzyme support, and most also only run if there is something to differentiate, thus the user applied the autodiff macro.
The same goes for the 200 lines in builder.rs, we lower the arguments passed into the autodiff macro to something that can be used by the enzyme pass.
There are 150 more lines remaining which handle ffi, based on Nikita's comment some seem duplicated, so I'll try to safe a few more lines here.

Copy link
Member

@davidtwco davidtwco left a comment

Choose a reason for hiding this comment

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

This might need another review pass but here are some initial comments

@@ -56,6 +56,10 @@ codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO
codegen_llvm_run_passes = failed to run LLVM passes
codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}
codegen_llvm_prepare_autodiff = failed to prepare AutoDiff: src: {$src}, target: {$target}, {$error}
codegen_llvm_prepare_autodiff_with_llvm_err = failed to prepare AutoDiff: {$llvm_err}, src: {$src}, target: {$target}, {$error}
Copy link
Member

Choose a reason for hiding this comment

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

nit: some diagnostics say "AutoDiff" and some "autodiff", would be nice if this were consistent

@@ -604,7 +604,12 @@ pub(crate) fn run_pass_manager(
debug!("running the pass manager");
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?;
// We will run this again with different values in the context of automatic differentiation.
let first_run = true;
Copy link
Member

Choose a reason for hiding this comment

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

Is this happening regardless of whether Enzyme is enabled?

Copy link
Contributor Author

@ZuseZ4 ZuseZ4 Nov 21, 2024

Choose a reason for hiding this comment

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

No, only if Enzyme support is enabled when building rustc, and if the user additionally applied at least one autodiff macro.
If that is the case we check that fat-lto is enabled (in the other PR), and then we will run opt passes twice.
The fat-lto requirement is something that will be lifted in the future.
Optimizing the whole module twice is also a bit more than what we really want, so I'll make that more granular in the future, to only optimize code that is getting differentiated twice. I'll add this to the comments.

}
};
let tgt_name = CString::new(item.target.clone()).unwrap();
dbg!("Target name: {:?}", &tgt_name);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
dbg!("Target name: {:?}", &tgt_name);
debug!("target name: {:?}", &tgt_name);

}));
}
};
let tgt_name = CString::new(item.target.clone()).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

nit: I'm not sure we use the tgt abbreviation anywhere

}
}

pub(crate) fn add_opt_dbg_helper2<'ll>(
Copy link
Member

Choose a reason for hiding this comment

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

This could do with a comment describing what it does

_ => {}
}

trace!("Matching args");
Copy link
Member

Choose a reason for hiding this comment

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

nit: this is the biggest nitpick, but we tend to have lowercase log messages

) -> Result<(), FatalError> {
if cgcx.lto != Lto::Fat {
let dcx = cgcx.create_dcx();
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO {}));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO {}));
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));

LtoModuleCodegen::Fat(module) => {
B::autodiff(cgcx, &module, diff_fncs, config)?;
}
_ => panic!("Unreachable? Autodiff called with non-fat LTO module"),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
_ => panic!("Unreachable? Autodiff called with non-fat LTO module"),
_ => panic!("autodiff called with non-fat LTO module"),

let md_todiff = llvm::LLVMMetadataAsValue(llcx, md);
let _md2 = llvm::LLVMSetMetadata(call, md_ty, md_todiff);
} else {
trace!("No dbg info");
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
trace!("No dbg info");
trace!("no dbg info");

// ret double %0
// }

unsafe {
Copy link
Member

Choose a reason for hiding this comment

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

Everything in this block needs more comments explaining what it is doing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-autodiff `#![feature(autodiff)]` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.