Post

GSoC 2026 Final Report: Bringing Autodiff and Offload into Rust CI

GSoC 2026 Final Report: Bringing Autodiff and Offload into Rust CI

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
  • 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:

Two main changes were required to distribute autodiff:

  • loading Enzyme dynamically only when autodiff is 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.

This post is licensed under CC BY 4.0 by the author.

Trending Tags