Skip to content
Merged
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
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_llvm/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. Did you install it via rustup?
codegen_llvm_autodiff_component_missing = autodiff backend not found in the sysroot: {$err}
.note = it will be distributed via rustup in the future

codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend: {$err}

codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable
codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_codegen_llvm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {

#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_component_unavailable)]
pub(crate) struct AutoDiffComponentUnavailable;
pub(crate) struct AutoDiffComponentUnavailable {
pub err: String,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_component_missing)]
#[note]
pub(crate) struct AutoDiffComponentMissing {
pub err: String,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_without_lto)]
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,14 @@ impl CodegenBackend for LlvmCodegenBackend {

use crate::back::lto::enable_autodiff_settings;
if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
if let Err(_) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable);
match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
Ok(_) => {}
Err(llvm::EnzymeLibraryError::NotFound { err }) => {
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err });
}
Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err });
}
}
enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
}
Expand Down
34 changes: 25 additions & 9 deletions compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub(crate) mod Enzyme_AD {
fn load_ptr_by_symbol_mut_void(
lib: &libloading::Library,
bytes: &[u8],
) -> Result<*mut c_void, Box<dyn std::error::Error>> {
) -> Result<*mut c_void, libloading::Error> {
unsafe {
let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
// libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some
Expand Down Expand Up @@ -192,15 +192,27 @@ pub(crate) mod Enzyme_AD {

static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();

#[derive(Debug)]
pub(crate) enum EnzymeLibraryError {
NotFound { err: String },
LoadFailed { err: String },
}

impl From<libloading::Error> for EnzymeLibraryError {
fn from(err: libloading::Error) -> Self {
Self::LoadFailed { err: format!("{err:?}") }
}
}

impl EnzymeWrapper {
/// Initialize EnzymeWrapper with the given sysroot if not already initialized.
/// Safe to call multiple times - subsequent calls are no-ops due to OnceLock.
pub(crate) fn get_or_init(
sysroot: &rustc_session::config::Sysroot,
) -> Result<MutexGuard<'static, Self>, Box<dyn std::error::Error>> {
) -> Result<MutexGuard<'static, Self>, EnzymeLibraryError> {
let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
let w = Self::call_dynamic(sysroot)?;
Ok::<_, Box<dyn std::error::Error>>(Mutex::new(w))
Ok::<_, EnzymeLibraryError>(Mutex::new(w))
})?;

Ok(mtx.lock().unwrap())
Expand Down Expand Up @@ -351,7 +363,7 @@ pub(crate) mod Enzyme_AD {
#[allow(non_snake_case)]
fn call_dynamic(
sysroot: &rustc_session::config::Sysroot,
) -> Result<Self, Box<dyn std::error::Error>> {
) -> Result<Self, EnzymeLibraryError> {
let enzyme_path = Self::get_enzyme_path(sysroot)?;
let lib = unsafe { libloading::Library::new(enzyme_path)? };

Expand Down Expand Up @@ -416,7 +428,7 @@ pub(crate) mod Enzyme_AD {
})
}

fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, String> {
fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, EnzymeLibraryError> {
let llvm_version_major = unsafe { LLVMRustVersionMajor() };

let path_buf = sysroot
Expand All @@ -434,15 +446,19 @@ pub(crate) mod Enzyme_AD {
.map(|p| p.join("lib").display().to_string())
.collect::<Vec<String>>()
.join("\n* ");
format!(
"failed to find a `libEnzyme-{llvm_version_major}` folder \
EnzymeLibraryError::NotFound {
err: format!(
"failed to find a `libEnzyme-{llvm_version_major}` folder \
in the sysroot candidates:\n* {candidates}"
)
),
}
})?;

Ok(path_buf
.to_str()
.ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))?
.ok_or_else(|| EnzymeLibraryError::LoadFailed {
err: format!("invalid UTF-8 in path: {}", path_buf.display()),
})?
.to_string())
}
}
Expand Down
Loading