GSoC 2026 Final Report: Bringing Autodiff and Offload into Rust CI
- Contributor: Shota Sugano
- Mentor: Manuel Drehwald
- Project: Bringing autodiff and offload into Rust CI
- Organization: The Rust Foundation
Overview
The goal of this project was to bring Rust’s automatic differentiation (autodiff) and GPU offloading support (offload) under CI coverage and into nightly distribution.
Before GSoC began, the status was:
autodiff- partially supported in CI
- built on Linux and on one Windows distribution runner, but not on macOS runners
- not tested by a CI job
- partially supported in CI
offload- neither distributed through nightly nor tested by a CI job
Distributing and testing these two components makes them easier to use and helps us catch regression earlier.
During GSoC, I completed the following work:
autodiff- enabled nightly distribution on aarch64 and x86_64 macOS
- added an optional x86_64 Linux CI test job
offload- made the offload-specific LLVM wrapper dynamically loadable
- added a partial nightly component for x86_64 Linux
std::autodiff
Distributing
Related PRs:
- (Before GSoC) feat: dlopen Enzyme
- (Before GSoC) cmake: make Enzyme Apple dynamic_lookup opt-in (EnzymeAD/Enzyme)
- (Before GSoC) Move aarch64-apple dist builder to dynamic llvm linking and enable autodiff in CI for it
- (Before GSoC) Link LLVM dynamically on aarch64-apple-darwin
- Link LLVM dynamically on aarch64-apple-darwin
- Enable Enzyme for aarch64-apple-darwin
- Update autodiff installation guide (rustc-dev-guide)
- Fix tablegen path in cross builds (EnzymeAD/Enzyme)
- Link LLVM dynamically on x86_64-apple
- Enable Enzyme on x86_64-apple
- Add autodiff support for x86_64 apple darwin (rustc-dev-guide)
Two main changes were required to distribute autodiff:
- loading Enzyme dynamically only when
autodiffis enabled - dynamically linking LLVM on macOS so that rustc and Enzyme use the same LLVM library
Before GSoC, we landed feat: dlopen Enzyme. This PR changed rustc to load Enzyme only when autodiff is enabled, allowing Enzyme to be distributed as a separate component instead of increasing the size of the rustc component itself.
However, macOS distribution was not yet ready for this setup. Compiling autodiff code could hang because rustc and Enzyme loaded separate copies of LLVM.
So, my first challenge was to distribute autodiff for aarch64-apple-darwin by linking LLVM dynamically on the target.
My first attempt broke Miri. Miri could not find an LLVM library because llvm-config reported the versioned shared library name such as LLVM-22-..., but the distributed toolchain provided only libLLVM.dylib. The second attempt normalized the link name to LLVM and added the sysroot library directory to the linker search path, which fixed Miri.
However, after the CI LLVM artifact was rebuilt, ./x build failed because llvm-config still expected the versioned file, so the change was reverted.
In the third attempt, I added a versioned-name symbolic link pointing to libLLVM.dylib, and the change landed successfully.
This naming issue was not unique to Rust. LLVM recently changed the default on Darwin to use versioned filenames, matching other platforms more closely.
During Rust’s update from LLVM 22 to LLVM 23, we temporarily disabled the new behavior and kept the previous unversioned naming on macOS. However, Rust may switch to versioned LLVM libraries on macOS in the future.
After that, I enabled Enzyme on aarch64-apple-darwin. This allows users to install the Enzyme component required by autodiff by running rustup +nightly component add enzyme.
Testing
Related PR:
After enabling autodiff distribution through nightly, I added an x86_64 Linux CI job that runs the autodiff test suite. The job is currently optional, so failures do not block PRs from being merged.
std::offload
Distributing
Related PRs:
As with autodiff, we decided to distribute offload separately from rustc. In the dlopen offload PR, I separated the offload-specific C++ wrapper from the main rustc LLVM wrapper and made rustc load it dynamically only when needed.
I then added a separate offload component to the x86_64 Linux distribution.
After adding the offload component to the nightly manifest, users can install it by running rustup +nightly component add offload.
However, the component is still partial. We still need some manual steps involving clang-linker-wrapper. Building and distributing clang-linker-wrapper itself would be straightforward, but doing so would require building Clang first, making CI even slower. It would also require shipping and invoking an additional binary.
A better approach would be to teach rustc to call the required LLVM APIs directly. I will continue investigating this after GSoC.
Testing
Related PR:
This work was not as high on the priority list as other work. End-to-end offload tests require GPU runners in CI, and my mentor, Manuel, is looking into providing GPU CI for AMD and NVIDIA. In the meantime, I started developing CPU-side CI tests for offload and will continue this work after GSoC.
Future Work
My next steps are to land the offload CI job and replace the remaining manual clang-linker-wrapper step with direct calls from rustc to the required LLVM APIs.
Acknowledgements
I would like to thank my mentor, Manuel Drehwald (@ZuseZ4) for his technical guidance during GSoC and since my first contribution to Enzyme last summer. I also thank Jakub Beránek (@Kobzol) for his guidance and reviews on CI infrastructure. I am also grateful to the Rust Foundation and Google for supporting my work through GSoC, and to the Rust community members who provided valuable feedback.