Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2274,23 +2274,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);
}

// Build the libraries for this compiler to link to (i.e., the libraries
Expand Down
49 changes: 49 additions & 0 deletions src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2592,6 +2592,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<GeneratedTarball>;
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<GeneratedTarball> {
// 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.
Expand Down
60 changes: 49 additions & 11 deletions src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ use std::path::{Path, PathBuf};
use std::sync::OnceLock;
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};
Expand Down Expand Up @@ -896,13 +898,28 @@ fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
.or_else(|| env::var_os(var_base))
}

#[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<'_> {
Expand All @@ -914,16 +931,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, .. } = builder.ensure(Llvm { target: self.target });

Expand All @@ -939,6 +956,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");
Expand All @@ -952,7 +975,15 @@ impl Step for Enzyme {
stamp.path().display()
));
}
return out_dir;
return BuiltEnzyme { enzyme: dylib };
}

let llvm_cmake_dir = builder.llvm_out(target).join("lib/cmake/llvm");
if !builder.config.dry_run() && !llvm_cmake_dir.is_dir() {
builder.info(&format!(
"WARNING: {} does not exist, Enzyme build will likely fail",
llvm_cmake_dir.display()
));
}

trace!(?target, "(re)building enzyme artifacts");
Expand All @@ -961,9 +992,6 @@ impl Step for Enzyme {
let _time = helpers::timeit(builder);
t!(fs::create_dir_all(&out_dir));

builder
.config
.update_submodule(Path::new("src").join("tools").join("enzyme").to_str().unwrap());
let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/"));
configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), &[]);

Expand All @@ -983,12 +1011,22 @@ impl Step for Enzyme {
.define("LLVM_ENABLE_ASSERTIONS", "ON")
.define("ENZYME_EXTERNAL_SHARED_LIB", "ON")
.define("ENZYME_BC_LOADER", "OFF")
.define("LLVM_DIR", builder.llvm_out(target));
.define("LLVM_DIR", llvm_cmake_dir);

cfg.build();

// At this point, `out_dir` should contain the built libEnzyme-<LLVM-version>.<dylib-ext>
// 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 }
}
}

Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,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
Expand Down
3 changes: 2 additions & 1 deletion src/bootstrap/src/core/config/toml/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub fn check_incompatible_options_for_ci_llvm(
enable_warnings,
download_ci_llvm: _,
build_config,
enzyme: _,
enzyme,
} = ci_llvm_config;

err!(current_llvm_config.optimize, optimize);
Expand All @@ -139,6 +139,7 @@ pub fn check_incompatible_options_for_ci_llvm(
err!(current_llvm_config.clang, clang);
err!(current_llvm_config.build_config, build_config);
err!(current_llvm_config.plugins, plugins);
err!(current_llvm_config.enzyme, enzyme);

warn!(current_llvm_config.enable_warnings, enable_warnings);

Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/src/utils/tarball.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub(crate) enum OverlayKind {
RustAnalyzer,
RustcCodegenCranelift,
LlvmBitcodeLinker,
Enzyme,
}

impl OverlayKind {
Expand All @@ -35,6 +36,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",
Expand Down Expand Up @@ -94,6 +96,7 @@ impl OverlayKind {
.version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")),
OverlayKind::RustcCodegenCranelift => builder.rust_version(),
OverlayKind::LlvmBitcodeLinker => builder.rust_version(),
OverlayKind::Enzyme => builder.rust_version(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
Loading