From 48739d64b8d22a61c49188b0c3b100843341730b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 16 Dec 2025 21:19:20 +0100 Subject: [PATCH 01/11] Refactor `Enzyme` step --- src/bootstrap/src/core/build_steps/compile.rs | 22 +++------ src/bootstrap/src/core/build_steps/llvm.rs | 47 +++++++++++++++---- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11f2a28bb935c..651ff03a8690a 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2292,23 +2292,13 @@ impl Step for Assemble { builder.compiler(target_compiler.stage - 1, builder.config.host_target); // Build enzyme - if builder.config.llvm_enzyme && !builder.config.dry_run() { + if builder.config.llvm_enzyme { debug!("`llvm_enzyme` requested"); - let enzyme_install = builder.ensure(llvm::Enzyme { target: build_compiler.host }); - if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) { - let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config); - let lib_ext = std::env::consts::DLL_EXTENSION; - let libenzyme = format!("libEnzyme-{llvm_version_major}"); - let src_lib = - enzyme_install.join("build/Enzyme").join(&libenzyme).with_extension(lib_ext); - let libdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host); - let target_libdir = - builder.sysroot_target_libdir(target_compiler, target_compiler.host); - let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext); - let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext); - builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary); - builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary); - } + let enzyme = builder.ensure(llvm::Enzyme { target: build_compiler.host }); + let target_libdir = + builder.sysroot_target_libdir(target_compiler, target_compiler.host); + let target_dst_lib = target_libdir.join(enzyme.enzyme_filename()); + builder.copy_link(&enzyme.enzyme_path(), &target_dst_lib, FileType::NativeLibrary); } if builder.config.llvm_offload && !builder.config.dry_run() { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index c3935d9810e99..f6a763b940753 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -17,6 +17,7 @@ use std::{env, fs}; use build_helper::exit; use build_helper::git::PathFreshness; +use crate::core::build_steps::llvm; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step, StepMetadata}; use crate::core::config::{Config, TargetSelection}; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; @@ -1077,13 +1078,28 @@ impl Step for OmpOffload { } } +#[derive(Clone)] +pub struct BuiltEnzyme { + /// Path to the libEnzyme dylib. + enzyme: PathBuf, +} + +impl BuiltEnzyme { + pub fn enzyme_path(&self) -> PathBuf { + self.enzyme.clone() + } + pub fn enzyme_filename(&self) -> String { + self.enzyme.file_name().unwrap().to_str().unwrap().to_owned() + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Enzyme { pub target: TargetSelection, } impl Step for Enzyme { - type Output = PathBuf; + type Output = BuiltEnzyme; const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1095,16 +1111,16 @@ impl Step for Enzyme { } /// Compile Enzyme for `target`. - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Self::Output { builder.require_submodule( "src/tools/enzyme", Some("The Enzyme sources are required for autodiff."), ); + let target = self.target; + if builder.config.dry_run() { - let out_dir = builder.enzyme_out(self.target); - return out_dir; + return BuiltEnzyme { enzyme: builder.config.tempdir().join("enzyme-dryrun") }; } - let target = self.target; let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); @@ -1120,6 +1136,12 @@ impl Step for Enzyme { let out_dir = builder.enzyme_out(target); let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash); + let llvm_version_major = llvm::get_llvm_version_major(builder, &host_llvm_config); + let lib_ext = std::env::consts::DLL_EXTENSION; + let libenzyme = format!("libEnzyme-{llvm_version_major}"); + let build_dir = out_dir.join("lib"); + let dylib = build_dir.join(&libenzyme).with_extension(lib_ext); + trace!("checking build stamp to see if we need to rebuild enzyme artifacts"); if stamp.is_up_to_date() { trace!(?out_dir, "enzyme build artifacts are up to date"); @@ -1133,7 +1155,7 @@ impl Step for Enzyme { stamp.path().display() )); } - return out_dir; + return BuiltEnzyme { enzyme: dylib }; } if !builder.config.dry_run() && !llvm_cmake_dir.is_dir() { @@ -1149,7 +1171,6 @@ impl Step for Enzyme { let _time = helpers::timeit(builder); t!(fs::create_dir_all(&out_dir)); - builder.config.update_submodule("src/tools/enzyme"); let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/")); // Enzyme devs maintain upstream compatibility, but only fix deprecations when they are about // to turn into a hard error. As such, Enzyme generates various warnings which could make it @@ -1178,8 +1199,18 @@ impl Step for Enzyme { cfg.build(); + // At this point, `out_dir` should contain the built libEnzyme-. + // file. + if !dylib.exists() { + eprintln!( + "`{libenzyme}` not found in `{}`. Either the build has failed or Enzyme was built with a wrong version of LLVM", + build_dir.display() + ); + exit!(1); + } + t!(stamp.write()); - out_dir + BuiltEnzyme { enzyme: dylib } } } From 0a01a8f8376898e190d5ac31b1d38fbb1bd49d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 16 Dec 2025 21:55:56 +0100 Subject: [PATCH 02/11] Add dist step for `Enzyme` --- src/bootstrap/src/core/build_steps/dist.rs | 49 ++++++++++++++++++++++ src/bootstrap/src/core/builder/mod.rs | 1 + src/bootstrap/src/utils/tarball.rs | 3 ++ 3 files changed, 53 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index cfcb144e0993e..8ba05a7fa3a7f 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2717,6 +2717,55 @@ impl Step for LlvmBitcodeLinker { } } +/// Distributes the `enzyme` library so that it can be used by a compiler whose host +/// is `target`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Enzyme { + /// Enzyme will by usable by rustc on this host. + pub target: TargetSelection, +} + +impl Step for Enzyme { + type Output = Option; + const IS_HOST: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("enzyme") + } + + fn is_default_step(builder: &Builder<'_>) -> bool { + builder.config.llvm_enzyme + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Enzyme { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + // This prevents Enzyme from being built for "dist" + // or "install" on the stable/beta channels. It is not yet stable and + // should not be included. + if !builder.build.unstable_features() { + return None; + } + + let target = self.target; + + let enzyme = builder.ensure(llvm::Enzyme { target }); + + let target_libdir = format!("lib/rustlib/{}/lib", target.triple); + + // Prepare the image directory + let mut tarball = Tarball::new(builder, "enzyme", &target.triple); + tarball.set_overlay(OverlayKind::Enzyme); + tarball.is_preview(true); + + tarball.add_file(enzyme.enzyme_path(), target_libdir, FileType::NativeLibrary); + + Some(tarball.generate()) + } +} + /// Tarball intended for internal consumption to ease rustc/std development. /// /// Should not be considered stable by end users. diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index f63b8e0445509..14cae2d0efc4b 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -980,6 +980,7 @@ impl<'a> Builder<'a> { dist::LlvmTools, dist::LlvmBitcodeLinker, dist::RustDev, + dist::Enzyme, dist::Bootstrap, dist::Extended, // It seems that PlainSourceTarball somehow changes how some of the tools diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index cd6a03c84870c..17d75e83daeac 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -28,6 +28,7 @@ pub(crate) enum OverlayKind { RustcCodegenGcc, Gcc, LlvmBitcodeLinker, + Enzyme, } impl OverlayKind { @@ -37,6 +38,7 @@ impl OverlayKind { OverlayKind::Llvm => { &["src/llvm-project/llvm/LICENSE.TXT", "src/llvm-project/llvm/README.txt"] } + OverlayKind::Enzyme => &["src/tools/enzyme/LICENSE", "src/tools/enzyme/Readme.md"], OverlayKind::Cargo => &[ "src/tools/cargo/README.md", "src/tools/cargo/LICENSE-MIT", @@ -111,6 +113,7 @@ impl OverlayKind { OverlayKind::RustcCodegenGcc => builder.rust_version(), OverlayKind::LlvmBitcodeLinker => builder.rust_version(), OverlayKind::Gcc => builder.rust_version(), + OverlayKind::Enzyme => builder.rust_version(), } } } From 80fe5dd37b3dc65a05c33946d7466e0da614211a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 16 Dec 2025 22:09:21 +0100 Subject: [PATCH 03/11] Enable Enzyme in CI --- src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index cb57478761994..a7ba2caf830ac 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -91,6 +91,7 @@ ENV RUST_CONFIGURE_ARGS \ --set llvm.thin-lto=true \ --set llvm.ninja=false \ --set llvm.libzstd=true \ + --set llvm.enzyme=true \ --set rust.jemalloc \ --set rust.bootstrap-override-lld=true \ --set rust.lto=thin \ From e538f4b009c03ce9f1d3da58cc0785444b7d22cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 17 Dec 2025 16:32:40 +0100 Subject: [PATCH 04/11] WIP: Disable tests --- src/tools/opt-dist/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index cdbeee63d6c26..01adecb1f1b12 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -188,7 +188,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024. .use_bolt(!is_aarch64) .skipped_tests(vec![]) - .run_tests(true) + .run_tests(false) .fast_try_build(is_fast_try_build) .build_llvm(true) .build()?; From 643cc78448ddef6b1eec9ffcd03a1ceb681b77c7 Mon Sep 17 00:00:00 2001 From: sgasho Date: Tue, 13 Jan 2026 23:29:57 +0900 Subject: [PATCH 05/11] set llvm.enzyme=true on dist-aarch64-apple --- src/ci/github-actions/jobs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 7411b394b94a4..1c88ce3b5e83e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -486,6 +486,7 @@ auto: --enable-full-tools --enable-sanitizers --enable-profiler + --set llvm.enzyme=true --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 From 31d3fde05be07944b1ccb7de9aa68b916265204b Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 17 Jan 2026 12:25:58 +0900 Subject: [PATCH 06/11] enable llvm.link-shared for dist-aarch64-apple --- src/ci/github-actions/jobs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1c88ce3b5e83e..dafd7580b7978 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -486,6 +486,7 @@ auto: --enable-full-tools --enable-sanitizers --enable-profiler + --set llvm.link-shared=true --set llvm.enzyme=true --set rust.jemalloc --set rust.lto=thin From 9594f3c9a2d63a91a085edd19ea8d52060e91351 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 17 Jan 2026 15:08:14 +0900 Subject: [PATCH 07/11] Revert "enable llvm.link-shared for dist-aarch64-apple" This reverts commit 31d3fde05be07944b1ccb7de9aa68b916265204b. --- src/ci/github-actions/jobs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index dafd7580b7978..1c88ce3b5e83e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -486,7 +486,6 @@ auto: --enable-full-tools --enable-sanitizers --enable-profiler - --set llvm.link-shared=true --set llvm.enzyme=true --set rust.jemalloc --set rust.lto=thin From 98144d4184816e8102796abd47fadfdeb1c401af Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 17 Jan 2026 16:03:35 +0900 Subject: [PATCH 08/11] export LLVM symbol when autodiff is enabled && on apple darwin platform --- compiler/rustc_codegen_ssa/src/back/linker.rs | 8 ++++++++ compiler/rustc_session/src/options.rs | 2 ++ src/bootstrap/src/core/build_steps/compile.rs | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 637d54dd06c65..7e22627fb083f 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -796,6 +796,14 @@ impl<'a> Linker for GccLinker<'a> { } } + if crate_type == CrateType::Dylib + && self.sess.target.is_like_darwin + && self.sess.opts.unstable_opts.export_llvm_symbols + && self.sess.opts.crate_name.as_deref() == Some("rustc_driver") + { + return; + } + // We manually create a list of exported symbols to ensure we don't expose any more. // The object files have far more public symbols than we actually want to export, // so we hide them all here. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 96bdcf8beffb9..3ccb4985551ed 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2367,6 +2367,8 @@ options! { "enable default bounds for experimental group of auto traits"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), + export_llvm_symbols: bool = (false, parse_bool, [TRACKED], + "export LLVM symbols from rustc_driver on darwin"), external_clangrt: bool = (false, parse_bool, [UNTRACKED], "rely on user specified linker commands to find clangrt"), extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 651ff03a8690a..75e5670f8547e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1261,6 +1261,10 @@ pub fn rustc_cargo( cargo.rustflag("-Zdefault-visibility=protected"); } + if builder.config.llvm_enzyme && target.contains("apple") { + cargo.rustflag("-Zexport-llvm-symbols"); + } + if is_lto_stage(build_compiler) { match builder.config.rust_lto { RustcLto::Thin | RustcLto::Fat => { From bc6658b517664e412c6633cde317bf4801916339 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 17 Jan 2026 16:34:27 +0900 Subject: [PATCH 09/11] temporarily switch enzyme submodule --- .gitmodules | 2 +- src/tools/enzyme | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8617643a12029..1d512d0a62325 100644 --- a/.gitmodules +++ b/.gitmodules @@ -41,7 +41,7 @@ shallow = true [submodule "src/tools/enzyme"] path = src/tools/enzyme - url = https://github.com/rust-lang/enzyme.git + url = https://github.com/sgasho/enzyme.git shallow = true [submodule "src/gcc"] path = src/gcc diff --git a/src/tools/enzyme b/src/tools/enzyme index 09f4820b78e2d..c2672d958e783 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit 09f4820b78e2d71b85a3278bbb41dc3a012e84dd +Subproject commit c2672d958e783a84687f5183bee875f4e2ddc60e From 5871afbe73ef475442acb8baf879d468eddd4c70 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sat, 17 Jan 2026 17:08:13 +0900 Subject: [PATCH 10/11] enables -Zexport-llvm-symbols only when stage1/2 --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 75e5670f8547e..a26bd94a54c20 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1261,7 +1261,7 @@ pub fn rustc_cargo( cargo.rustflag("-Zdefault-visibility=protected"); } - if builder.config.llvm_enzyme && target.contains("apple") { + if builder.config.llvm_enzyme && target.contains("apple") && build_compiler.stage != 0 { cargo.rustflag("-Zexport-llvm-symbols"); } From e43279f10d738c97a2de490a002f25d902b25db5 Mon Sep 17 00:00:00 2001 From: sgasho Date: Tue, 20 Jan 2026 23:46:52 +0900 Subject: [PATCH 11/11] update enzyme submodule --- src/tools/enzyme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/enzyme b/src/tools/enzyme index c2672d958e783..479b5887eed66 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit c2672d958e783a84687f5183bee875f4e2ddc60e +Subproject commit 479b5887eed66451bc53cc122144975a1d3b8abb