From e1258e79d6cb709b26ded97d32de6c55f355e2aa Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Sat, 23 Aug 2025 20:17:32 +0000
Subject: autodiff: Add basic TypeTree with NoTT flag
Signed-off-by: Karan Janthe
---
compiler/rustc_codegen_llvm/src/back/lto.rs | 2 ++
1 file changed, 2 insertions(+)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 78107d95e5a..5ac3a87c158 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -563,6 +563,8 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
config::AutoDiff::Enable => {}
// We handle this below
config::AutoDiff::NoPostopt => {}
+ // Disables TypeTree generation
+ config::AutoDiff::NoTT => {}
}
}
// This helps with handling enums for now.
--
cgit 1.4.1-3-g733a5
From 375e14ef491ac7bfa701e269b2815625abf2fca6 Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Sat, 23 Aug 2025 21:56:56 +0000
Subject: Add TypeTree metadata attachment for autodiff
- Add F128 support to TypeTree Kind enum
- Implement TypeTree FFI bindings and conversion functions
- Add typetree.rs module for metadata attachment to LLVM functions
- Integrate TypeTree generation with autodiff intrinsic pipeline
- Support scalar types: f32, f64, integers, f16, f128
- Attach enzyme_type attributes as LLVM string metadata for Enzyme
Signed-off-by: Karan Janthe
---
compiler/rustc_ast/src/expand/typetree.rs | 1 +
.../rustc_codegen_llvm/src/builder/autodiff.rs | 6 +
compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +
compiler/rustc_codegen_llvm/src/lib.rs | 1 +
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 182 ++++++++++++++++++++-
compiler/rustc_codegen_llvm/src/typetree.rs | 144 ++++++++++++++++
compiler/rustc_middle/src/ty/mod.rs | 19 +--
7 files changed, 343 insertions(+), 14 deletions(-)
create mode 100644 compiler/rustc_codegen_llvm/src/typetree.rs
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_ast/src/expand/typetree.rs b/compiler/rustc_ast/src/expand/typetree.rs
index 9a2dd2e85e0..e7b4f3aff41 100644
--- a/compiler/rustc_ast/src/expand/typetree.rs
+++ b/compiler/rustc_ast/src/expand/typetree.rs
@@ -31,6 +31,7 @@ pub enum Kind {
Half,
Float,
Double,
+ F128,
Unknown,
}
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index b66e3dfdeec..c3485f56391 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -1,6 +1,7 @@
use std::ptr;
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
+use rustc_ast::expand::typetree::FncTree;
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv};
@@ -294,6 +295,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
fn_args: &[&'ll Value],
attrs: AutoDiffAttrs,
dest: PlaceRef<'tcx, &'ll Value>,
+ fnc_tree: FncTree,
) {
// We have to pick the name depending on whether we want forward or reverse mode autodiff.
let mut ad_name: String = match attrs.mode {
@@ -370,6 +372,10 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
fn_args,
);
+ if !fnc_tree.args.is_empty() || !fnc_tree.ret.0.is_empty() {
+ crate::typetree::add_tt(cx.llmod, cx.llcx, fn_to_diff, fnc_tree);
+ }
+
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
builder.store_to_place(call, dest.val);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e7f4a357048..3254b318651 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1213,6 +1213,9 @@ fn codegen_autodiff<'ll, 'tcx>(
&mut diff_attrs.input_activity,
);
+ let fnc_tree =
+ rustc_middle::ty::fnc_typetrees(tcx, fn_source.ty(tcx, TypingEnv::fully_monomorphized()));
+
// Build body
generate_enzyme_call(
bx,
@@ -1223,6 +1226,7 @@ fn codegen_autodiff<'ll, 'tcx>(
&val_arr,
diff_attrs.clone(),
result,
+ fnc_tree,
);
}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 6fb23d09843..a5ac789285d 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -67,6 +67,7 @@ mod llvm_util;
mod mono_item;
mod type_;
mod type_of;
+mod typetree;
mod va_arg;
mod value;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 695435eb6da..12b6ffa3c0b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -3,9 +3,35 @@
use libc::{c_char, c_uint};
use super::MetadataKindId;
-use super::ffi::{AttributeKind, BasicBlock, Metadata, Module, Type, Value};
+use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value};
use crate::llvm::{Bool, Builder};
+// TypeTree types
+pub(crate) type CTypeTreeRef = *mut EnzymeTypeTree;
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct EnzymeTypeTree {
+ _unused: [u8; 0],
+}
+
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub(crate) enum CConcreteType {
+ DT_Anything = 0,
+ DT_Integer = 1,
+ DT_Pointer = 2,
+ DT_Half = 3,
+ DT_Float = 4,
+ DT_Double = 5,
+ DT_Unknown = 6,
+}
+
+pub(crate) struct TypeTree {
+ pub(crate) inner: CTypeTreeRef,
+}
+
#[link(name = "llvm-wrapper", kind = "static")]
unsafe extern "C" {
// Enzyme
@@ -68,10 +94,33 @@ pub(crate) mod Enzyme_AD {
use libc::c_void;
+ use super::{CConcreteType, CTypeTreeRef, Context};
+
unsafe extern "C" {
pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8);
pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char);
}
+
+ // TypeTree functions
+ unsafe extern "C" {
+ pub(crate) fn EnzymeNewTypeTree() -> CTypeTreeRef;
+ pub(crate) fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef;
+ pub(crate) fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef;
+ pub(crate) fn EnzymeFreeTypeTree(CTT: CTypeTreeRef);
+ pub(crate) fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool;
+ pub(crate) fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64);
+ pub(crate) fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef);
+ pub(crate) fn EnzymeTypeTreeShiftIndiciesEq(
+ arg1: CTypeTreeRef,
+ data_layout: *const c_char,
+ offset: i64,
+ max_size: i64,
+ add_offset: u64,
+ );
+ pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char;
+ pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char);
+ }
+
unsafe extern "C" {
static mut EnzymePrintPerf: c_void;
static mut EnzymePrintActivity: c_void;
@@ -141,6 +190,57 @@ pub(crate) use self::Fallback_AD::*;
pub(crate) mod Fallback_AD {
#![allow(unused_variables)]
+ use libc::c_char;
+
+ use super::{CConcreteType, CTypeTreeRef, Context};
+
+ // TypeTree function fallbacks
+ pub(crate) unsafe fn EnzymeNewTypeTree() -> CTypeTreeRef {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeFreeTypeTree(CTT: CTypeTreeRef) {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64) {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef) {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeTypeTreeShiftIndiciesEq(
+ arg1: CTypeTreeRef,
+ data_layout: *const c_char,
+ offset: i64,
+ max_size: i64,
+ add_offset: u64,
+ ) {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char {
+ unimplemented!()
+ }
+
+ pub(crate) unsafe fn EnzymeTypeTreeToStringFree(arg1: *const c_char) {
+ unimplemented!()
+ }
+
pub(crate) fn set_inline(val: bool) {
unimplemented!()
}
@@ -169,3 +269,83 @@ pub(crate) mod Fallback_AD {
unimplemented!()
}
}
+
+impl TypeTree {
+ pub(crate) fn new() -> TypeTree {
+ let inner = unsafe { EnzymeNewTypeTree() };
+ TypeTree { inner }
+ }
+
+ pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree {
+ let inner = unsafe { EnzymeNewTypeTreeCT(t, ctx) };
+ TypeTree { inner }
+ }
+
+ pub(crate) fn merge(self, other: Self) -> Self {
+ unsafe {
+ EnzymeMergeTypeTree(self.inner, other.inner);
+ }
+ drop(other);
+ self
+ }
+
+ #[must_use]
+ pub(crate) fn shift(
+ self,
+ layout: &str,
+ offset: isize,
+ max_size: isize,
+ add_offset: usize,
+ ) -> Self {
+ let layout = std::ffi::CString::new(layout).unwrap();
+
+ unsafe {
+ EnzymeTypeTreeShiftIndiciesEq(
+ self.inner,
+ layout.as_ptr(),
+ offset as i64,
+ max_size as i64,
+ add_offset as u64,
+ );
+ }
+
+ self
+ }
+}
+
+impl Clone for TypeTree {
+ fn clone(&self) -> Self {
+ let inner = unsafe { EnzymeNewTypeTreeTR(self.inner) };
+ TypeTree { inner }
+ }
+}
+
+impl std::fmt::Display for TypeTree {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let ptr = unsafe { EnzymeTypeTreeToString(self.inner) };
+ let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
+ match cstr.to_str() {
+ Ok(x) => write!(f, "{}", x)?,
+ Err(err) => write!(f, "could not parse: {}", err)?,
+ }
+
+ // delete C string pointer
+ unsafe {
+ EnzymeTypeTreeToStringFree(ptr);
+ }
+
+ Ok(())
+ }
+}
+
+impl std::fmt::Debug for TypeTree {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ ::fmt(self, f)
+ }
+}
+
+impl Drop for TypeTree {
+ fn drop(&mut self) {
+ unsafe { EnzymeFreeTypeTree(self.inner) }
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
new file mode 100644
index 00000000000..434316464e6
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -0,0 +1,144 @@
+use std::ffi::{CString, c_char, c_uint};
+
+use rustc_ast::expand::typetree::{FncTree, TypeTree as RustTypeTree};
+
+use crate::attributes;
+use crate::llvm::{self, Value};
+
+/// Converts a Rust TypeTree to Enzyme's internal TypeTree format
+///
+/// This function takes a Rust-side TypeTree (from rustc_ast::expand::typetree)
+/// and converts it to Enzyme's internal C++ TypeTree representation that
+/// Enzyme can understand during differentiation analysis.
+#[cfg(llvm_enzyme)]
+fn to_enzyme_typetree(
+ rust_typetree: RustTypeTree,
+ data_layout: &str,
+ llcx: &llvm::Context,
+) -> llvm::TypeTree {
+ // Start with an empty TypeTree
+ let mut enzyme_tt = llvm::TypeTree::new();
+
+ // Convert each Type in the Rust TypeTree to Enzyme format
+ for rust_type in rust_typetree.0 {
+ let concrete_type = match rust_type.kind {
+ rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything,
+ rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer,
+ rustc_ast::expand::typetree::Kind::Pointer => llvm::CConcreteType::DT_Pointer,
+ rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half,
+ rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float,
+ rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double,
+ rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_Unknown,
+ rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown,
+ };
+
+ // Create a TypeTree for this specific type
+ let type_tt = llvm::TypeTree::from_type(concrete_type, llcx);
+
+ // Apply offset if specified
+ let type_tt = if rust_type.offset == -1 {
+ type_tt // -1 means everywhere/no specific offset
+ } else {
+ // Apply specific offset positioning
+ type_tt.shift(data_layout, rust_type.offset, rust_type.size as isize, 0)
+ };
+
+ // Merge this type into the main TypeTree
+ enzyme_tt = enzyme_tt.merge(type_tt);
+ }
+
+ enzyme_tt
+}
+
+#[cfg(not(llvm_enzyme))]
+fn to_enzyme_typetree(
+ _rust_typetree: RustTypeTree,
+ _data_layout: &str,
+ _llcx: &llvm::Context,
+) -> ! {
+ unimplemented!("TypeTree conversion not available without llvm_enzyme support")
+}
+
+// Attaches TypeTree information to LLVM function as enzyme_type attributes.
+#[cfg(llvm_enzyme)]
+pub(crate) fn add_tt<'ll>(
+ llmod: &'ll llvm::Module,
+ llcx: &'ll llvm::Context,
+ fn_def: &'ll Value,
+ tt: FncTree,
+) {
+ let inputs = tt.args;
+ let ret_tt: RustTypeTree = tt.ret;
+
+ // Get LLVM data layout string for TypeTree conversion
+ let llvm_data_layout: *const c_char = unsafe { llvm::LLVMGetDataLayoutStr(&*llmod) };
+ let llvm_data_layout =
+ std::str::from_utf8(unsafe { std::ffi::CStr::from_ptr(llvm_data_layout) }.to_bytes())
+ .expect("got a non-UTF8 data-layout from LLVM");
+
+ // Attribute name that Enzyme recognizes for TypeTree information
+ let attr_name = "enzyme_type";
+ let c_attr_name = CString::new(attr_name).unwrap();
+
+ // Attach TypeTree attributes to each input parameter
+ // Enzyme uses these to understand parameter memory layouts during differentiation
+ for (i, input) in inputs.iter().enumerate() {
+ unsafe {
+ // Convert Rust TypeTree to Enzyme's internal format
+ let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx);
+
+ // Serialize TypeTree to string format that Enzyme can parse
+ let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
+ let c_str = std::ffi::CStr::from_ptr(c_str);
+
+ // Create LLVM string attribute with TypeTree information
+ let attr = llvm::LLVMCreateStringAttribute(
+ llcx,
+ c_attr_name.as_ptr(),
+ c_attr_name.as_bytes().len() as c_uint,
+ c_str.as_ptr(),
+ c_str.to_bytes().len() as c_uint,
+ );
+
+ // Attach attribute to the specific function parameter
+ // Note: ArgumentPlace uses 0-based indexing, but LLVM uses 1-based for arguments
+ attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]);
+
+ // Free the C string to prevent memory leaks
+ llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
+ }
+ }
+
+ // Attach TypeTree attribute to the return type
+ // Enzyme needs this to understand how to handle return value derivatives
+ unsafe {
+ let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx);
+ let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
+ let c_str = std::ffi::CStr::from_ptr(c_str);
+
+ let ret_attr = llvm::LLVMCreateStringAttribute(
+ llcx,
+ c_attr_name.as_ptr(),
+ c_attr_name.as_bytes().len() as c_uint,
+ c_str.as_ptr(),
+ c_str.to_bytes().len() as c_uint,
+ );
+
+ // Attach to function return type
+ attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]);
+
+ // Free the C string
+ llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
+ }
+}
+
+// Fallback implementation when Enzyme is not available
+#[cfg(not(llvm_enzyme))]
+pub(crate) fn add_tt<'ll>(
+ _llmod: &'ll llvm::Module,
+ _llcx: &'ll llvm::Context,
+ _fn_def: &'ll Value,
+ _tt: FncTree,
+) {
+ unimplemented!()
+}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index df42c400317..e7130757f1d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2251,36 +2251,29 @@ pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree {
/// Generate TypeTree for a specific type.
/// This function analyzes a Rust type and creates appropriate TypeTree metadata.
-fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
- // Handle basic scalar types
+pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
if ty.is_scalar() {
let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() {
(Kind::Integer, ty.primitive_size(tcx).bytes_usize())
} else if ty.is_floating_point() {
match ty {
+ x if x == tcx.types.f16 => (Kind::Half, 2),
x if x == tcx.types.f32 => (Kind::Float, 4),
x if x == tcx.types.f64 => (Kind::Double, 8),
- _ => return TypeTree::new(), // Unknown float type
+ x if x == tcx.types.f128 => (Kind::F128, 16),
+ _ => return TypeTree::new(),
}
} else {
- // TODO(KMJ-007): Handle other scalar types if needed
return TypeTree::new();
};
-
- return TypeTree(vec![Type {
- offset: -1,
- size,
- kind,
- child: TypeTree::new()
- }]);
+
+ return TypeTree(vec![Type { offset: -1, size, kind, child: TypeTree::new() }]);
}
- // Handle references and pointers
if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() {
let inner_ty = if let Some(inner) = ty.builtin_deref(true) {
inner
} else {
- // TODO(KMJ-007): Handle complex pointer types
return TypeTree::new();
};
--
cgit 1.4.1-3-g733a5
From 664e83b3e76b51fb5192e74a64eef3bc5bbd4e32 Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Sat, 23 Aug 2025 23:10:48 +0000
Subject: added typetree support for memcpy
---
compiler/rustc_codegen_gcc/src/builder.rs | 1 +
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 1 +
compiler/rustc_codegen_llvm/src/abi.rs | 1 +
compiler/rustc_codegen_llvm/src/builder.rs | 15 +++++++--
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 +
compiler/rustc_codegen_llvm/src/typetree.rs | 20 ++++-------
compiler/rustc_codegen_llvm/src/va_arg.rs | 1 +
compiler/rustc_codegen_ssa/src/mir/block.rs | 1 +
compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 2 +-
compiler/rustc_codegen_ssa/src/mir/statement.rs | 2 +-
compiler/rustc_codegen_ssa/src/traits/builder.rs | 3 +-
compiler/rustc_interface/src/tests.rs | 1 -
compiler/rustc_middle/src/ty/mod.rs | 4 +--
tests/codegen-llvm/autodiff/typetree.rs | 2 +-
.../type-trees/memcpy-typetree/memcpy-ir.check | 8 +++++
.../type-trees/memcpy-typetree/memcpy.check | 13 ++++++++
.../autodiff/type-trees/memcpy-typetree/memcpy.rs | 36 ++++++++++++++++++++
.../autodiff/type-trees/memcpy-typetree/rmake.rs | 39 ++++++++++++++++++++++
.../autodiff/type-trees/nott-flag/rmake.rs | 14 +++-----
.../run-make/autodiff/type-trees/nott-flag/test.rs | 2 +-
tests/ui/autodiff/flag_nott.rs | 2 +-
21 files changed, 135 insertions(+), 34 deletions(-)
create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check
create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check
create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs
create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index f7a7a3f8c7e..5657620879c 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1383,6 +1383,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
_src_align: Align,
size: RValue<'gcc>,
flags: MemFlags,
+ _tt: Option, // Autodiff TypeTrees are LLVM-only, ignored in GCC backend
) {
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported");
let size = self.intcast(size, self.type_size_t(), false);
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 84fa56cf903..3b897a19835 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -771,6 +771,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
scratch_align,
bx.const_usize(self.layout.size.bytes()),
MemFlags::empty(),
+ None,
);
bx.lifetime_end(scratch, scratch_size);
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 11be7041167..61fadad6066 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -246,6 +246,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
scratch_align,
bx.const_usize(copy_bytes),
MemFlags::empty(),
+ None,
);
bx.lifetime_end(llscratch, scratch_size);
}
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 0f17cc9063a..83a9cf620f1 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -2,6 +2,7 @@ use std::borrow::{Borrow, Cow};
use std::ops::Deref;
use std::{iter, ptr};
+use rustc_ast::expand::typetree::FncTree;
pub(crate) mod autodiff;
pub(crate) mod gpu_offload;
@@ -1107,11 +1108,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
src_align: Align,
size: &'ll Value,
flags: MemFlags,
+ tt: Option,
) {
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported");
let size = self.intcast(size, self.type_isize(), false);
let is_volatile = flags.contains(MemFlags::VOLATILE);
- unsafe {
+ let memcpy = unsafe {
llvm::LLVMRustBuildMemCpy(
self.llbuilder,
dst,
@@ -1120,7 +1122,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
src_align.bytes() as c_uint,
size,
is_volatile,
- );
+ )
+ };
+
+ // TypeTree metadata for memcpy is especially important: when Enzyme encounters
+ // a memcpy during autodiff, it needs to know the structure of the data being
+ // copied to properly track derivatives. For example, copying an array of floats
+ // vs. copying a struct with mixed types requires different derivative handling.
+ // The TypeTree tells Enzyme exactly what memory layout to expect.
+ if let Some(tt) = tt {
+ crate::typetree::add_tt(self.cx().llmod, self.cx().llcx, memcpy, tt);
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 12b6ffa3c0b..9dd84ad9a4d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -25,6 +25,7 @@ pub(crate) enum CConcreteType {
DT_Half = 3,
DT_Float = 4,
DT_Double = 5,
+ // FIXME(KMJ-007): handle f128 using long double here(https://github.com/EnzymeAD/Enzyme/issues/1600)
DT_Unknown = 6,
}
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
index 434316464e6..8e6272a186b 100644
--- a/compiler/rustc_codegen_llvm/src/typetree.rs
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -1,8 +1,11 @@
-use std::ffi::{CString, c_char, c_uint};
-
-use rustc_ast::expand::typetree::{FncTree, TypeTree as RustTypeTree};
+use rustc_ast::expand::typetree::FncTree;
+#[cfg(llvm_enzyme)]
+use {
+ crate::attributes,
+ rustc_ast::expand::typetree::TypeTree as RustTypeTree,
+ std::ffi::{CString, c_char, c_uint},
+};
-use crate::attributes;
use crate::llvm::{self, Value};
/// Converts a Rust TypeTree to Enzyme's internal TypeTree format
@@ -50,15 +53,6 @@ fn to_enzyme_typetree(
enzyme_tt
}
-#[cfg(not(llvm_enzyme))]
-fn to_enzyme_typetree(
- _rust_typetree: RustTypeTree,
- _data_layout: &str,
- _llcx: &llvm::Context,
-) -> ! {
- unimplemented!("TypeTree conversion not available without llvm_enzyme support")
-}
-
// Attaches TypeTree information to LLVM function as enzyme_type attributes.
#[cfg(llvm_enzyme)]
pub(crate) fn add_tt<'ll>(
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index ab08125217f..d48c7cf874a 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -738,6 +738,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
src_align,
bx.const_u32(layout.layout.size().bytes() as u32),
MemFlags::empty(),
+ None,
);
tmp
} else {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 1b218a0d339..b2dc4fe32b0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1626,6 +1626,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
align,
bx.const_usize(copy_bytes),
MemFlags::empty(),
+ None,
);
// ...and then load it with the ABI type.
llval = load_cast(bx, cast, llscratch, scratch_align);
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 3c667b8e882..befa00c6861 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -30,7 +30,7 @@ fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
if allow_overlap {
bx.memmove(dst, align, src, align, size, flags);
} else {
- bx.memcpy(dst, align, src, align, size, flags);
+ bx.memcpy(dst, align, src, align, size, flags, None);
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index f164e0f9123..0a50d7f18db 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -90,7 +90,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let align = pointee_layout.align;
let dst = dst_val.immediate();
let src = src_val.immediate();
- bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
+ bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty(), None);
}
mir::StatementKind::FakeRead(..)
| mir::StatementKind::Retag { .. }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 4a5694e97fa..60296e36e0c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -451,6 +451,7 @@ pub trait BuilderMethods<'a, 'tcx>:
src_align: Align,
size: Self::Value,
flags: MemFlags,
+ tt: Option,
);
fn memmove(
&mut self,
@@ -507,7 +508,7 @@ pub trait BuilderMethods<'a, 'tcx>:
temp.val.store_with_flags(self, dst.with_type(layout), flags);
} else if !layout.is_zst() {
let bytes = self.const_usize(layout.size.bytes());
- self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags);
+ self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None);
}
}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 837acdadd57..0dc5b5af3ac 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -765,7 +765,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(allow_features, Some(vec![String::from("lang_items")]));
tracked!(always_encode_mir, true);
tracked!(assume_incomplete_release, true);
- tracked!(autodiff, vec![AutoDiff::Enable]);
tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]);
tracked!(binary_dep_depinfo, true);
tracked!(box_noalias, false);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index e7130757f1d..741b5d7fd4e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2280,12 +2280,12 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
let child = typetree_from_ty(tcx, inner_ty);
return TypeTree(vec![Type {
offset: -1,
- size: 8, // TODO(KMJ-007): Get actual pointer size from target
+ size: tcx.data_layout.pointer_size().bytes_usize(),
kind: Kind::Pointer,
child,
}]);
}
- // TODO(KMJ-007): Handle arrays, slices, structs, and other complex types
+ // FIXME(KMJ-007): Handle arrays, slices, structs, and other complex types
TypeTree::new()
}
diff --git a/tests/codegen-llvm/autodiff/typetree.rs b/tests/codegen-llvm/autodiff/typetree.rs
index 3ad38d581b9..1cb0c2fb68b 100644
--- a/tests/codegen-llvm/autodiff/typetree.rs
+++ b/tests/codegen-llvm/autodiff/typetree.rs
@@ -30,4 +30,4 @@ fn main() {
let output_ = d_simple(&x, &mut df_dx, 1.0);
assert_eq!(output, output_);
assert_eq!(2.0, df_dx);
-}
\ No newline at end of file
+}
diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check
new file mode 100644
index 00000000000..3a59f06dda1
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check
@@ -0,0 +1,8 @@
+; Check that enzyme_type attributes are present in the LLVM IR function definition
+; This verifies our TypeTree system correctly attaches metadata for Enzyme
+
+CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_memcpy({{.*}}"enzyme_type"="{[]:Pointer}"
+
+; Check that llvm.memcpy exists (either call or declare)
+CHECK: {{(call|declare).*}}@llvm.memcpy
+
diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check
new file mode 100644
index 00000000000..ae70830297a
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check
@@ -0,0 +1,13 @@
+CHECK: force_memcpy
+
+CHECK: @llvm.memcpy.p0.p0.i64
+
+CHECK: test_memcpy - {[-1]:Float@double} |{[-1]:Pointer}:{}
+
+CHECK-DAG: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double, [-1,8]:Float@double, [-1,16]:Float@double, [-1,24]:Float@double}
+
+CHECK-DAG: load double{{.*}}: {[-1]:Float@double}
+
+CHECK-DAG: fmul double{{.*}}: {[-1]:Float@double}
+
+CHECK-DAG: fadd double{{.*}}: {[-1]:Float@double}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs
new file mode 100644
index 00000000000..3c1029190c8
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs
@@ -0,0 +1,36 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+use std::ptr;
+
+#[inline(never)]
+fn force_memcpy(src: *const f64, dst: *mut f64, count: usize) {
+ unsafe {
+ ptr::copy_nonoverlapping(src, dst, count);
+ }
+}
+
+#[autodiff_reverse(d_test_memcpy, Duplicated, Active)]
+#[no_mangle]
+fn test_memcpy(input: &[f64; 128]) -> f64 {
+ let mut local_data = [0.0f64; 128];
+
+ // Use a separate function to prevent inlining and optimization
+ force_memcpy(input.as_ptr(), local_data.as_mut_ptr(), 128);
+
+ // Sum only first few elements to keep the computation simple
+ local_data[0] * local_data[0]
+ + local_data[1] * local_data[1]
+ + local_data[2] * local_data[2]
+ + local_data[3] * local_data[3]
+}
+
+fn main() {
+ let input = [1.0; 128];
+ let mut d_input = [0.0; 128];
+ let result = test_memcpy(&input);
+ let result_d = d_test_memcpy(&input, &mut d_input, 1.0);
+
+ assert_eq!(result, result_d);
+ println!("Memcpy test passed: result = {}", result);
+}
diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs
new file mode 100644
index 00000000000..b4c650330fe
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs
@@ -0,0 +1,39 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+ // First, compile to LLVM IR to check for enzyme_type attributes
+ let _ir_output = rustc()
+ .input("memcpy.rs")
+ .arg("-Zautodiff=Enable")
+ .arg("-Zautodiff=NoPostopt")
+ .opt_level("0")
+ .arg("--emit=llvm-ir")
+ .arg("-o")
+ .arg("main.ll")
+ .run();
+
+ // Then compile with TypeTree analysis output for the existing checks
+ let output = rustc()
+ .input("memcpy.rs")
+ .arg("-Zautodiff=Enable,PrintTAFn=test_memcpy")
+ .arg("-Zautodiff=NoPostopt")
+ .opt_level("3")
+ .arg("-Clto=fat")
+ .arg("-g")
+ .run();
+
+ let stdout = output.stdout_utf8();
+ let stderr = output.stderr_utf8();
+ let ir_content = rfs::read_to_string("main.ll");
+
+ rfs::write("memcpy.stdout", &stdout);
+ rfs::write("memcpy.stderr", &stderr);
+ rfs::write("main.ir", &ir_content);
+
+ llvm_filecheck().patterns("memcpy.check").stdin_buf(stdout).run();
+
+ llvm_filecheck().patterns("memcpy-ir.check").stdin_buf(ir_content).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs
index bab863ca9ff..de540b990ca 100644
--- a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs
+++ b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs
@@ -23,14 +23,8 @@ fn main() {
.run();
// Verify NoTT version does NOT have enzyme_type attributes
- llvm_filecheck()
- .patterns("nott.check")
- .stdin_buf(rfs::read("nott.ll"))
- .run();
-
+ llvm_filecheck().patterns("nott.check").stdin_buf(rfs::read("nott.ll")).run();
+
// Verify TypeTree version DOES have enzyme_type attributes
- llvm_filecheck()
- .patterns("with_tt.check")
- .stdin_buf(rfs::read("with_tt.ll"))
- .run();
-}
\ No newline at end of file
+ llvm_filecheck().patterns("with_tt.check").stdin_buf(rfs::read("with_tt.ll")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/nott-flag/test.rs b/tests/run-make/autodiff/type-trees/nott-flag/test.rs
index 5c634eea035..de3549c37c6 100644
--- a/tests/run-make/autodiff/type-trees/nott-flag/test.rs
+++ b/tests/run-make/autodiff/type-trees/nott-flag/test.rs
@@ -12,4 +12,4 @@ fn main() {
let x = 2.0;
let mut dx = 0.0;
let _result = d_square(&x, &mut dx, 1.0);
-}
\ No newline at end of file
+}
diff --git a/tests/ui/autodiff/flag_nott.rs b/tests/ui/autodiff/flag_nott.rs
index 7a97d892cd8..faa9949fe81 100644
--- a/tests/ui/autodiff/flag_nott.rs
+++ b/tests/ui/autodiff/flag_nott.rs
@@ -16,4 +16,4 @@ fn main() {
let x = 2.0;
let mut dx = 0.0;
let result = d_square(&x, &mut dx, 1.0);
-}
\ No newline at end of file
+}
--
cgit 1.4.1-3-g733a5
From 54f9376660707d4ca9fce51fd423658f75128ac4 Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Wed, 27 Aug 2025 18:23:54 +0000
Subject: autodiff: f128 support added for typetree
---
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 2 +-
compiler/rustc_codegen_llvm/src/typetree.rs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 9dd84ad9a4d..1596dc48379 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -25,8 +25,8 @@ pub(crate) enum CConcreteType {
DT_Half = 3,
DT_Float = 4,
DT_Double = 5,
- // FIXME(KMJ-007): handle f128 using long double here(https://github.com/EnzymeAD/Enzyme/issues/1600)
DT_Unknown = 6,
+ DT_FP128 = 9,
}
pub(crate) struct TypeTree {
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
index 8e6272a186b..8c0d255bba8 100644
--- a/compiler/rustc_codegen_llvm/src/typetree.rs
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -31,7 +31,7 @@ fn to_enzyme_typetree(
rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half,
rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float,
rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double,
- rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_Unknown,
+ rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_FP128,
rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown,
};
--
cgit 1.4.1-3-g733a5
From 4f3f0f48e7b1e61818b2bcbe4451f89bb4f47049 Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Thu, 4 Sep 2025 11:17:34 +0000
Subject: autodiff: fixed test to be more precise for type tree checking
---
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 23 +++++++
compiler/rustc_codegen_llvm/src/typetree.rs | 70 +++++++++-------------
compiler/rustc_middle/src/ty/mod.rs | 36 +++--------
.../autodiff/type-trees/array-typetree/array.check | 2 +-
.../type-trees/memcpy-typetree/memcpy-ir.check | 2 +-
.../type-trees/mixed-struct-typetree/mixed.check | 2 +
.../type-trees/mixed-struct-typetree/rmake.rs | 16 +++++
.../type-trees/mixed-struct-typetree/test.rs | 23 +++++++
.../autodiff/type-trees/nott-flag/with_tt.check | 2 +-
.../scalar-types/f128-typetree/f128.check | 4 +-
.../type-trees/scalar-types/f16-typetree/f16.check | 4 +-
.../type-trees/scalar-types/f32-typetree/f32.check | 2 +-
.../type-trees/scalar-types/f64-typetree/f64.check | 2 +-
.../type-trees/scalar-types/i32-typetree/i32.check | 4 +-
.../type-trees/scalar-types/i32-typetree/test.rs | 7 ++-
.../autodiff/type-trees/slice-typetree/slice.check | 2 +-
.../type-trees/struct-typetree/struct.check | 2 +-
.../autodiff/type-trees/tuple-typetree/tuple.check | 2 +-
.../type-trees/type-analysis/vec/vec.check | 2 +-
19 files changed, 120 insertions(+), 87 deletions(-)
create mode 100644 tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check
create mode 100644 tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs
create mode 100644 tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 1596dc48379..e63043b2122 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -118,6 +118,13 @@ pub(crate) mod Enzyme_AD {
max_size: i64,
add_offset: u64,
);
+ pub(crate) fn EnzymeTypeTreeInsertEq(
+ CTT: CTypeTreeRef,
+ indices: *const i64,
+ len: usize,
+ ct: CConcreteType,
+ ctx: &Context,
+ );
pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char;
pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char);
}
@@ -234,6 +241,16 @@ pub(crate) mod Fallback_AD {
unimplemented!()
}
+ pub(crate) unsafe fn EnzymeTypeTreeInsertEq(
+ CTT: CTypeTreeRef,
+ indices: *const i64,
+ len: usize,
+ ct: CConcreteType,
+ ctx: &Context,
+ ) {
+ unimplemented!()
+ }
+
pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char {
unimplemented!()
}
@@ -312,6 +329,12 @@ impl TypeTree {
self
}
+
+ pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) {
+ unsafe {
+ EnzymeTypeTreeInsertEq(self.inner, indices.as_ptr(), indices.len(), ct, ctx);
+ }
+ }
}
impl Clone for TypeTree {
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
index 8c0d255bba8..ae6a2da62b5 100644
--- a/compiler/rustc_codegen_llvm/src/typetree.rs
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -8,22 +8,24 @@ use {
use crate::llvm::{self, Value};
-/// Converts a Rust TypeTree to Enzyme's internal TypeTree format
-///
-/// This function takes a Rust-side TypeTree (from rustc_ast::expand::typetree)
-/// and converts it to Enzyme's internal C++ TypeTree representation that
-/// Enzyme can understand during differentiation analysis.
#[cfg(llvm_enzyme)]
fn to_enzyme_typetree(
rust_typetree: RustTypeTree,
- data_layout: &str,
+ _data_layout: &str,
llcx: &llvm::Context,
) -> llvm::TypeTree {
- // Start with an empty TypeTree
let mut enzyme_tt = llvm::TypeTree::new();
-
- // Convert each Type in the Rust TypeTree to Enzyme format
- for rust_type in rust_typetree.0 {
+ process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx);
+ enzyme_tt
+}
+#[cfg(llvm_enzyme)]
+fn process_typetree_recursive(
+ enzyme_tt: &mut llvm::TypeTree,
+ rust_typetree: &RustTypeTree,
+ parent_indices: &[i64],
+ llcx: &llvm::Context,
+) {
+ for rust_type in &rust_typetree.0 {
let concrete_type = match rust_type.kind {
rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything,
rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer,
@@ -35,25 +37,27 @@ fn to_enzyme_typetree(
rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown,
};
- // Create a TypeTree for this specific type
- let type_tt = llvm::TypeTree::from_type(concrete_type, llcx);
-
- // Apply offset if specified
- let type_tt = if rust_type.offset == -1 {
- type_tt // -1 means everywhere/no specific offset
+ let mut indices = parent_indices.to_vec();
+ if !parent_indices.is_empty() {
+ if rust_type.offset == -1 {
+ indices.push(-1);
+ } else {
+ indices.push(rust_type.offset as i64);
+ }
+ } else if rust_type.offset == -1 {
+ indices.push(-1);
} else {
- // Apply specific offset positioning
- type_tt.shift(data_layout, rust_type.offset, rust_type.size as isize, 0)
- };
+ indices.push(rust_type.offset as i64);
+ }
- // Merge this type into the main TypeTree
- enzyme_tt = enzyme_tt.merge(type_tt);
- }
+ enzyme_tt.insert(&indices, concrete_type, llcx);
- enzyme_tt
+ if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer && !rust_type.child.0.is_empty() {
+ process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx);
+ }
+ }
}
-// Attaches TypeTree information to LLVM function as enzyme_type attributes.
#[cfg(llvm_enzyme)]
pub(crate) fn add_tt<'ll>(
llmod: &'ll llvm::Module,
@@ -64,28 +68,20 @@ pub(crate) fn add_tt<'ll>(
let inputs = tt.args;
let ret_tt: RustTypeTree = tt.ret;
- // Get LLVM data layout string for TypeTree conversion
let llvm_data_layout: *const c_char = unsafe { llvm::LLVMGetDataLayoutStr(&*llmod) };
let llvm_data_layout =
std::str::from_utf8(unsafe { std::ffi::CStr::from_ptr(llvm_data_layout) }.to_bytes())
.expect("got a non-UTF8 data-layout from LLVM");
- // Attribute name that Enzyme recognizes for TypeTree information
let attr_name = "enzyme_type";
let c_attr_name = CString::new(attr_name).unwrap();
- // Attach TypeTree attributes to each input parameter
- // Enzyme uses these to understand parameter memory layouts during differentiation
for (i, input) in inputs.iter().enumerate() {
unsafe {
- // Convert Rust TypeTree to Enzyme's internal format
let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx);
-
- // Serialize TypeTree to string format that Enzyme can parse
let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
let c_str = std::ffi::CStr::from_ptr(c_str);
- // Create LLVM string attribute with TypeTree information
let attr = llvm::LLVMCreateStringAttribute(
llcx,
c_attr_name.as_ptr(),
@@ -94,17 +90,11 @@ pub(crate) fn add_tt<'ll>(
c_str.to_bytes().len() as c_uint,
);
- // Attach attribute to the specific function parameter
- // Note: ArgumentPlace uses 0-based indexing, but LLVM uses 1-based for arguments
attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]);
-
- // Free the C string to prevent memory leaks
llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
}
}
- // Attach TypeTree attribute to the return type
- // Enzyme needs this to understand how to handle return value derivatives
unsafe {
let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx);
let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
@@ -118,15 +108,11 @@ pub(crate) fn add_tt<'ll>(
c_str.to_bytes().len() as c_uint,
);
- // Attach to function return type
attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]);
-
- // Free the C string
llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
}
}
-// Fallback implementation when Enzyme is not available
#[cfg(not(llvm_enzyme))]
pub(crate) fn add_tt<'ll>(
_llmod: &'ll llvm::Module,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 703d417f96d..581f20e8492 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2261,10 +2261,10 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
x if x == tcx.types.f32 => (Kind::Float, 4),
x if x == tcx.types.f64 => (Kind::Double, 8),
x if x == tcx.types.f128 => (Kind::F128, 16),
- _ => return TypeTree::new(),
+ _ => (Kind::Integer, 0),
}
} else {
- return TypeTree::new();
+ (Kind::Integer, 0)
};
return TypeTree(vec![Type { offset: -1, size, kind, child: TypeTree::new() }]);
@@ -2295,32 +2295,14 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
let element_tree = typetree_from_ty(tcx, *element_ty);
- let element_layout = tcx
- .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*element_ty))
- .ok()
- .map(|layout| layout.size.bytes_usize())
- .unwrap_or(0);
-
- if element_layout == 0 {
- return TypeTree::new();
- }
-
let mut types = Vec::new();
- for i in 0..len {
- let base_offset = (i as usize * element_layout) as isize;
-
- for elem_type in &element_tree.0 {
- types.push(Type {
- offset: if elem_type.offset == -1 {
- base_offset
- } else {
- base_offset + elem_type.offset
- },
- size: elem_type.size,
- kind: elem_type.kind,
- child: elem_type.child.clone(),
- });
- }
+ for elem_type in &element_tree.0 {
+ types.push(Type {
+ offset: -1,
+ size: elem_type.size,
+ kind: elem_type.kind,
+ child: elem_type.child.clone(),
+ });
}
return TypeTree(types);
diff --git a/tests/run-make/autodiff/type-trees/array-typetree/array.check b/tests/run-make/autodiff/type-trees/array-typetree/array.check
index 7513458b8ab..0d38bdec17e 100644
--- a/tests/run-make/autodiff/type-trees/array-typetree/array.check
+++ b/tests/run-make/autodiff/type-trees/array-typetree/array.check
@@ -1,4 +1,4 @@
; Check that array TypeTree metadata is correctly generated
; Should show Float@double at each array element offset (0, 8, 16, 24, 32 bytes)
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_array{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_array{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check
index 3a59f06dda1..0e6351ac4d3 100644
--- a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check
+++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check
@@ -1,7 +1,7 @@
; Check that enzyme_type attributes are present in the LLVM IR function definition
; This verifies our TypeTree system correctly attaches metadata for Enzyme
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_memcpy({{.*}}"enzyme_type"="{[]:Pointer}"
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_memcpy({{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
; Check that llvm.memcpy exists (either call or declare)
CHECK: {{(call|declare).*}}@llvm.memcpy
diff --git a/tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check
new file mode 100644
index 00000000000..584f5840843
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check
@@ -0,0 +1,2 @@
+; Check that mixed struct with large array generates correct detailed type tree
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_mixed_struct{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Integer, [-1,8]:Float@float}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs
new file mode 100644
index 00000000000..1c19963bc36
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs
@@ -0,0 +1,16 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+ rustc()
+ .input("test.rs")
+ .arg("-Zautodiff=Enable")
+ .arg("-Zautodiff=NoPostopt")
+ .opt_level("0")
+ .emit("llvm-ir")
+ .run();
+
+ llvm_filecheck().patterns("mixed.check").stdin_buf(rfs::read("test.ll")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs
new file mode 100644
index 00000000000..7a734980e61
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs
@@ -0,0 +1,23 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[repr(C)]
+struct Container {
+ header: i64,
+ data: [f32; 1000],
+}
+
+#[autodiff_reverse(d_test, Duplicated, Active)]
+#[no_mangle]
+#[inline(never)]
+fn test_mixed_struct(container: &Container) -> f32 {
+ container.data[0] + container.data[999]
+}
+
+fn main() {
+ let container = Container { header: 42, data: [1.0; 1000] };
+ let mut d_container = Container { header: 0, data: [0.0; 1000] };
+ let result = d_test(&container, &mut d_container, 1.0);
+ std::hint::black_box(result);
+}
diff --git a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check
index 53eafc10a65..3c02003c882 100644
--- a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check
+++ b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check
@@ -1,4 +1,4 @@
// Check that enzyme_type attributes are present when TypeTree is enabled
// This verifies our TypeTree metadata attachment is working
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check
index 31cef113420..733e46aa45a 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check
@@ -1,4 +1,4 @@
; Check that f128 TypeTree metadata is correctly generated
-; f128 maps to Unknown in our current implementation since CConcreteType doesn't have DT_F128
+; Should show Float@fp128 for f128 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"={{.*}}@test_f128{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@fp128}"{{.*}}@test_f128{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@fp128}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check
index 97a3964a569..9caca26b5cf 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check
@@ -1,4 +1,4 @@
; Check that f16 TypeTree metadata is correctly generated
-; Should show Half for f16 values and Pointer for references
+; Should show Float@half for f16 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"={{.*}}@test_f16{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@half}"{{.*}}@test_f16{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@half}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check
index b32d5086d07..ec12ba6b234 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check
@@ -1,4 +1,4 @@
; Check that f32 TypeTree metadata is correctly generated
; Should show Float@float for f32 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@float}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check
index 0e9d9c03a0f..f1af270824d 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check
@@ -1,4 +1,4 @@
; Check that f64 TypeTree metadata is correctly generated
; Should show Float@double for f64 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check
index aa8e5223e8e..fd9a94be810 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check
@@ -1,4 +1,4 @@
; Check that i32 TypeTree metadata is correctly generated
-; Should show Integer for i32 values (integers are typically Const in autodiff)
+; Should show Integer for i32 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[]:Integer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Integer}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs
index 530c137f62b..249803c5d9f 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs
+++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs
@@ -2,13 +2,14 @@
use std::autodiff::autodiff_reverse;
-#[autodiff_reverse(d_test, Const, Active)]
+#[autodiff_reverse(d_test, Duplicated, Active)]
#[no_mangle]
-fn test_i32(x: i32) -> i32 {
+fn test_i32(x: &i32) -> i32 {
x * x
}
fn main() {
let x = 5_i32;
- let _result = d_test(x, 1);
+ let mut dx = 0_i32;
+ let _result = d_test(&x, &mut dx, 1);
}
diff --git a/tests/run-make/autodiff/type-trees/slice-typetree/slice.check b/tests/run-make/autodiff/type-trees/slice-typetree/slice.check
index 8fc9e9c4f1b..6543b616115 100644
--- a/tests/run-make/autodiff/type-trees/slice-typetree/slice.check
+++ b/tests/run-make/autodiff/type-trees/slice-typetree/slice.check
@@ -1,4 +1,4 @@
; Check that slice TypeTree metadata is correctly generated
; Should show Float@double for slice elements
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_slice{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_slice{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/struct-typetree/struct.check b/tests/run-make/autodiff/type-trees/struct-typetree/struct.check
index 2f763f18c1c..54956317e1e 100644
--- a/tests/run-make/autodiff/type-trees/struct-typetree/struct.check
+++ b/tests/run-make/autodiff/type-trees/struct-typetree/struct.check
@@ -1,4 +1,4 @@
; Check that struct TypeTree metadata is correctly generated
; Should show Float@double at offsets 0, 8, 16 for Point struct fields
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_struct{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_struct{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double, [-1,8]:Float@double, [-1,16]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check b/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check
index 50aa25e96ae..47647e78cc3 100644
--- a/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check
+++ b/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check
@@ -1,4 +1,4 @@
; Check that tuple TypeTree metadata is correctly generated
; Should show Float@double at offsets 0, 8, 16 for (f64, f64, f64)
-CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_tuple{{.*}}"enzyme_type"="{[]:Pointer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_tuple{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double, [-1,8]:Float@double, [-1,16]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check
index dcf9508b69d..cdb70eb83fc 100644
--- a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check
+++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check
@@ -1,7 +1,7 @@
// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer}
// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer}
-// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !102, !noundef !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !{{[0-9]+}}, !noundef !{{[0-9]+}}: {}
// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 16, !dbg !{{[0-9]+}}: {[-1]:Pointer}
// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {}
// CHECK-DAG: %{{[0-9]+}} = icmp eq i64 %{{[0-9]+}}, 0, !dbg !{{[0-9]+}}: {[-1]:Integer}
--
cgit 1.4.1-3-g733a5
From 4520926bb527bd43edbf0de84c2b0c6a9c5fc5ce Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Thu, 11 Sep 2025 07:30:35 +0000
Subject: autodiff: recurion added for typetree
---
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 +
compiler/rustc_codegen_llvm/src/typetree.rs | 10 +--
compiler/rustc_middle/src/ty/mod.rs | 76 ++++++++++++++--
.../autodiff/type-trees/nott-flag/with_tt.check | 2 +-
.../type-trees/recursion-typetree/recursion.check | 3 +
.../type-trees/recursion-typetree/rmake.rs | 9 ++
.../autodiff/type-trees/recursion-typetree/test.rs | 100 +++++++++++++++++++++
.../scalar-types/f128-typetree/f128.check | 2 +-
.../type-trees/scalar-types/f16-typetree/f16.check | 2 +-
.../type-trees/scalar-types/f32-typetree/f32.check | 2 +-
.../type-trees/scalar-types/f64-typetree/f64.check | 2 +-
.../type-trees/scalar-types/i32-typetree/i32.check | 2 +-
12 files changed, 191 insertions(+), 20 deletions(-)
create mode 100644 tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check
create mode 100644 tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs
create mode 100644 tests/run-make/autodiff/type-trees/recursion-typetree/test.rs
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index e63043b2122..b604f5139c8 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -127,6 +127,7 @@ pub(crate) mod Enzyme_AD {
);
pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char;
pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char);
+ pub(crate) fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint;
}
unsafe extern "C" {
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
index ae6a2da62b5..1a54884f6c5 100644
--- a/compiler/rustc_codegen_llvm/src/typetree.rs
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -39,11 +39,7 @@ fn process_typetree_recursive(
let mut indices = parent_indices.to_vec();
if !parent_indices.is_empty() {
- if rust_type.offset == -1 {
- indices.push(-1);
- } else {
- indices.push(rust_type.offset as i64);
- }
+ indices.push(rust_type.offset as i64);
} else if rust_type.offset == -1 {
indices.push(-1);
} else {
@@ -52,7 +48,9 @@ fn process_typetree_recursive(
enzyme_tt.insert(&indices, concrete_type, llcx);
- if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer && !rust_type.child.0.is_empty() {
+ if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer
+ && !rust_type.child.0.is_empty()
+ {
process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx);
}
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 581f20e8492..7ca2355947a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2252,6 +2252,61 @@ pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree {
/// Generate TypeTree for a specific type.
/// This function analyzes a Rust type and creates appropriate TypeTree metadata.
pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
+ let mut visited = Vec::new();
+ typetree_from_ty_inner(tcx, ty, 0, &mut visited)
+}
+
+/// Internal recursive function for TypeTree generation with cycle detection and depth limiting.
+fn typetree_from_ty_inner<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ depth: usize,
+ visited: &mut Vec>,
+) -> TypeTree {
+ #[cfg(llvm_enzyme)]
+ {
+ unsafe extern "C" {
+ fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint;
+ }
+ let max_depth = unsafe { EnzymeGetMaxTypeDepth() } as usize;
+ if depth > max_depth {
+ return TypeTree::new();
+ }
+ }
+
+ #[cfg(not(llvm_enzyme))]
+ if depth > 6 {
+ return TypeTree::new();
+ }
+
+ if visited.contains(&ty) {
+ return TypeTree::new();
+ }
+
+ visited.push(ty);
+ let result = typetree_from_ty_impl(tcx, ty, depth, visited);
+ visited.pop();
+ result
+}
+
+/// Implementation of TypeTree generation logic.
+fn typetree_from_ty_impl<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ depth: usize,
+ visited: &mut Vec>,
+) -> TypeTree {
+ typetree_from_ty_impl_inner(tcx, ty, depth, visited, false)
+}
+
+/// Internal implementation with context about whether this is for a reference target.
+fn typetree_from_ty_impl_inner<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ depth: usize,
+ visited: &mut Vec>,
+ is_reference_target: bool,
+) -> TypeTree {
if ty.is_scalar() {
let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() {
(Kind::Integer, ty.primitive_size(tcx).bytes_usize())
@@ -2267,7 +2322,10 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
(Kind::Integer, 0)
};
- return TypeTree(vec![Type { offset: -1, size, kind, child: TypeTree::new() }]);
+ // Use offset 0 for scalars that are direct targets of references (like &f64)
+ // Use offset -1 for scalars used directly (like function return types)
+ let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 };
+ return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]);
}
if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() {
@@ -2277,7 +2335,7 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
return TypeTree::new();
};
- let child = typetree_from_ty(tcx, inner_ty);
+ let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true);
return TypeTree(vec![Type {
offset: -1,
size: tcx.data_layout.pointer_size().bytes_usize(),
@@ -2292,9 +2350,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
if len == 0 {
return TypeTree::new();
}
-
- let element_tree = typetree_from_ty(tcx, *element_ty);
-
+ let element_tree =
+ typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false);
let mut types = Vec::new();
for elem_type in &element_tree.0 {
types.push(Type {
@@ -2311,7 +2368,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
if ty.is_slice() {
if let ty::Slice(element_ty) = ty.kind() {
- let element_tree = typetree_from_ty(tcx, *element_ty);
+ let element_tree =
+ typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false);
return element_tree;
}
}
@@ -2325,7 +2383,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
let mut current_offset = 0;
for tuple_ty in tuple_types.iter() {
- let element_tree = typetree_from_ty(tcx, tuple_ty);
+ let element_tree =
+ typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false);
let element_layout = tcx
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty))
@@ -2361,7 +2420,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
for (field_idx, field_def) in adt_def.all_fields().enumerate() {
let field_ty = field_def.ty(tcx, args);
- let field_tree = typetree_from_ty(tcx, field_ty);
+ let field_tree =
+ typetree_from_ty_impl_inner(tcx, field_ty, depth + 1, visited, false);
let field_offset = layout.fields.offset(field_idx).bytes_usize();
diff --git a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check
index 3c02003c882..0b4c9119179 100644
--- a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check
+++ b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check
@@ -1,4 +1,4 @@
// Check that enzyme_type attributes are present when TypeTree is enabled
// This verifies our TypeTree metadata attachment is working
-CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check b/tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check
new file mode 100644
index 00000000000..1960e7b816c
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check
@@ -0,0 +1,3 @@
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_deep{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}"
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_graph{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Integer, [-1,8]:Integer, [-1,16]:Integer, [-1,24]:Float@double}"
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_node{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs
new file mode 100644
index 00000000000..78718f3a215
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs
@@ -0,0 +1,9 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+ rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run();
+ llvm_filecheck().patterns("recursion.check").stdin_buf(rfs::read("test.ll")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/recursion-typetree/test.rs b/tests/run-make/autodiff/type-trees/recursion-typetree/test.rs
new file mode 100644
index 00000000000..9d40bec1bf1
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/recursion-typetree/test.rs
@@ -0,0 +1,100 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+// Self-referential struct to test recursion detection
+#[derive(Clone)]
+struct Node {
+ value: f64,
+ next: Option>,
+}
+
+// Mutually recursive structs to test cycle detection
+#[derive(Clone)]
+struct GraphNodeA {
+ value: f64,
+ connections: Vec,
+}
+
+#[derive(Clone)]
+struct GraphNodeB {
+ weight: f64,
+ target: Option>,
+}
+
+#[autodiff_reverse(d_test_node, Duplicated, Active)]
+#[no_mangle]
+fn test_node(node: &Node) -> f64 {
+ node.value * 2.0
+}
+
+#[autodiff_reverse(d_test_graph, Duplicated, Active)]
+#[no_mangle]
+fn test_graph(a: &GraphNodeA) -> f64 {
+ a.value * 3.0
+}
+
+// Simple depth test - deeply nested but not circular
+#[derive(Clone)]
+struct Level1 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level2 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level3 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level4 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level5 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level6 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level7 {
+ val: f64,
+ next: Option>,
+}
+#[derive(Clone)]
+struct Level8 {
+ val: f64,
+}
+
+#[autodiff_reverse(d_test_deep, Duplicated, Active)]
+#[no_mangle]
+fn test_deep(deep: &Level1) -> f64 {
+ deep.val * 4.0
+}
+
+fn main() {
+ let node = Node { value: 1.0, next: None };
+
+ let graph = GraphNodeA { value: 2.0, connections: vec![] };
+
+ let deep = Level1 { val: 5.0, next: None };
+
+ let mut d_node = Node { value: 0.0, next: None };
+
+ let mut d_graph = GraphNodeA { value: 0.0, connections: vec![] };
+
+ let mut d_deep = Level1 { val: 0.0, next: None };
+
+ let _result1 = d_test_node(&node, &mut d_node, 1.0);
+ let _result2 = d_test_graph(&graph, &mut d_graph, 1.0);
+ let _result3 = d_test_deep(&deep, &mut d_deep, 1.0);
+}
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check
index 733e46aa45a..23db64eea52 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check
@@ -1,4 +1,4 @@
; Check that f128 TypeTree metadata is correctly generated
; Should show Float@fp128 for f128 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@fp128}"{{.*}}@test_f128{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@fp128}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@fp128}"{{.*}}@test_f128{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@fp128}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check
index 9caca26b5cf..9adff68d36f 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check
@@ -1,4 +1,4 @@
; Check that f16 TypeTree metadata is correctly generated
; Should show Float@half for f16 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@half}"{{.*}}@test_f16{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@half}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@half}"{{.*}}@test_f16{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@half}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check
index ec12ba6b234..176630f57e8 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check
@@ -1,4 +1,4 @@
; Check that f32 TypeTree metadata is correctly generated
; Should show Float@float for f32 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@float}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check
index f1af270824d..929cd379694 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check
@@ -1,4 +1,4 @@
; Check that f64 TypeTree metadata is correctly generated
; Should show Float@double for f64 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}"
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check
index fd9a94be810..dee4aa5bbb6 100644
--- a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check
+++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check
@@ -1,4 +1,4 @@
; Check that i32 TypeTree metadata is correctly generated
; Should show Integer for i32 values and Pointer for references
-CHECK: define{{.*}}"enzyme_type"="{[-1]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Integer}"
\ No newline at end of file
+CHECK: define{{.*}}"enzyme_type"="{[-1]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Integer}"
\ No newline at end of file
--
cgit 1.4.1-3-g733a5
From b1a9f231fea0459356f751ad6c1704b55f541118 Mon Sep 17 00:00:00 2001
From: Zalathar
Date: Fri, 19 Sep 2025 14:41:18 +1000
Subject: Use `LLVMDIBuilderGetOrCreateSubrange`
---
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +-
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 15 +++++++--------
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 ------
3 files changed, 8 insertions(+), 15 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index aa8b8bd152d..c3712e5b744 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -117,7 +117,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
.try_to_target_usize(cx.tcx)
.expect("expected monomorphic const in codegen") as c_longlong;
- let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) };
+ let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) };
let subscripts = &[subrange];
let di_node = unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 1124ebc3d44..d125c1c9c29 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -25,7 +25,7 @@ use rustc_target::spec::SymbolVisibility;
use super::RustString;
use super::debuginfo::{
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
- DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange,
+ DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram,
DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
};
use crate::llvm;
@@ -890,7 +890,6 @@ pub(crate) mod debuginfo {
pub(crate) type DIVariable = DIDescriptor;
pub(crate) type DIGlobalVariableExpression = DIDescriptor;
pub(crate) type DIArray = DIDescriptor;
- pub(crate) type DISubrange = DIDescriptor;
pub(crate) type DIEnumerator = DIDescriptor;
pub(crate) type DITemplateTypeParameter = DIDescriptor;
@@ -1989,6 +1988,12 @@ unsafe extern "C" {
Scope: Option<&'ll Metadata>,
AlignInBits: u32, // (optional; default is 0)
) -> &'ll Metadata;
+
+ pub(crate) fn LLVMDIBuilderGetOrCreateSubrange<'ll>(
+ Builder: &DIBuilder<'ll>,
+ LowerBound: i64,
+ Count: i64,
+ ) -> &'ll Metadata;
}
#[link(name = "llvm-wrapper", kind = "static")]
@@ -2370,12 +2375,6 @@ unsafe extern "C" {
AlignInBits: u32,
) -> &'a DIVariable;
- pub(crate) fn LLVMRustDIBuilderGetOrCreateSubrange<'a>(
- Builder: &DIBuilder<'a>,
- Lo: i64,
- Count: i64,
- ) -> &'a DISubrange;
-
pub(crate) fn LLVMRustDIBuilderGetOrCreateArray<'a>(
Builder: &DIBuilder<'a>,
Ptr: *const Option<&'a DIDescriptor>,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 64151962321..de79c3e6861 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1142,12 +1142,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
}
}
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo,
- int64_t Count) {
- return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count));
-}
-
extern "C" LLVMMetadataRef
LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder,
LLVMMetadataRef *Ptr, unsigned Count) {
--
cgit 1.4.1-3-g733a5
From a6d261712ee546fc1fc1b7b7c0ee0782aa827b8b Mon Sep 17 00:00:00 2001
From: Zalathar
Date: Fri, 19 Sep 2025 14:44:54 +1000
Subject: Use `LLVMDIBuilderGetOrCreateArray`
---
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs | 2 +-
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 12 ++++++------
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 9 ---------
3 files changed, 7 insertions(+), 16 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index cc1d504b430..7e1e49310f6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -28,7 +28,7 @@ pub(crate) fn create_DIArray<'ll>(
builder: &DIBuilder<'ll>,
arr: &[Option<&'ll DIDescriptor>],
) -> &'ll DIArray {
- unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }
+ unsafe { llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len()) }
}
#[inline]
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index d125c1c9c29..290dbda77f6 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1994,6 +1994,12 @@ unsafe extern "C" {
LowerBound: i64,
Count: i64,
) -> &'ll Metadata;
+
+ pub(crate) fn LLVMDIBuilderGetOrCreateArray<'ll>(
+ Builder: &DIBuilder<'ll>,
+ Data: *const Option<&'ll Metadata>,
+ NumElements: size_t,
+ ) -> &'ll Metadata;
}
#[link(name = "llvm-wrapper", kind = "static")]
@@ -2375,12 +2381,6 @@ unsafe extern "C" {
AlignInBits: u32,
) -> &'a DIVariable;
- pub(crate) fn LLVMRustDIBuilderGetOrCreateArray<'a>(
- Builder: &DIBuilder<'a>,
- Ptr: *const Option<&'a DIDescriptor>,
- Count: c_uint,
- ) -> &'a DIArray;
-
pub(crate) fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>(
Builder: &DIBuilder<'a>,
Val: &'a Value,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index de79c3e6861..b7878692176 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1142,15 +1142,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
}
}
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder,
- LLVMMetadataRef *Ptr, unsigned Count) {
- Metadata **DataValue = unwrap(Ptr);
- return wrap(unwrap(Builder)
- ->getOrCreateArray(ArrayRef(DataValue, Count))
- .get());
-}
-
extern "C" void
LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
LLVMMetadataRef VarInfo, uint64_t *AddrOps,
--
cgit 1.4.1-3-g733a5
From 3ba5f19182bf7144c54cbbd0b7af3d4fe76b5317 Mon Sep 17 00:00:00 2001
From: Karan Janthe
Date: Fri, 12 Sep 2025 06:11:18 +0000
Subject: autodiff: typetree recursive depth query from enzyme with fallback
Signed-off-by: Karan Janthe
---
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 -
compiler/rustc_codegen_llvm/src/typetree.rs | 10 +++++-----
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 12 ++++++++++++
compiler/rustc_middle/src/ty/mod.rs | 21 +++++++--------------
src/llvm-project | 2 +-
src/tools/cargo | 2 +-
6 files changed, 26 insertions(+), 22 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index b604f5139c8..e63043b2122 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -127,7 +127,6 @@ pub(crate) mod Enzyme_AD {
);
pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char;
pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char);
- pub(crate) fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint;
}
unsafe extern "C" {
diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs
index 1a54884f6c5..7e263503700 100644
--- a/compiler/rustc_codegen_llvm/src/typetree.rs
+++ b/compiler/rustc_codegen_llvm/src/typetree.rs
@@ -1,5 +1,5 @@
use rustc_ast::expand::typetree::FncTree;
-#[cfg(llvm_enzyme)]
+#[cfg(feature = "llvm_enzyme")]
use {
crate::attributes,
rustc_ast::expand::typetree::TypeTree as RustTypeTree,
@@ -8,7 +8,7 @@ use {
use crate::llvm::{self, Value};
-#[cfg(llvm_enzyme)]
+#[cfg(feature = "llvm_enzyme")]
fn to_enzyme_typetree(
rust_typetree: RustTypeTree,
_data_layout: &str,
@@ -18,7 +18,7 @@ fn to_enzyme_typetree(
process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx);
enzyme_tt
}
-#[cfg(llvm_enzyme)]
+#[cfg(feature = "llvm_enzyme")]
fn process_typetree_recursive(
enzyme_tt: &mut llvm::TypeTree,
rust_typetree: &RustTypeTree,
@@ -56,7 +56,7 @@ fn process_typetree_recursive(
}
}
-#[cfg(llvm_enzyme)]
+#[cfg(feature = "llvm_enzyme")]
pub(crate) fn add_tt<'ll>(
llmod: &'ll llvm::Module,
llcx: &'ll llvm::Context,
@@ -111,7 +111,7 @@ pub(crate) fn add_tt<'ll>(
}
}
-#[cfg(not(llvm_enzyme))]
+#[cfg(not(feature = "llvm_enzyme"))]
pub(crate) fn add_tt<'ll>(
_llmod: &'ll llvm::Module,
_llcx: &'ll llvm::Context,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 64151962321..c1a924a87e4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1847,3 +1847,15 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
MD.NoHWAddress = true;
GV.setSanitizerMetadata(MD);
}
+
+#ifdef ENZYME
+extern "C" {
+extern llvm::cl::opt EnzymeMaxTypeDepth;
+}
+
+extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return EnzymeMaxTypeDepth; }
+#else
+extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() {
+ return 6; // Default fallback depth
+}
+#endif
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7ca2355947a..ce4de6b95e0 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -63,7 +63,7 @@ pub use rustc_type_ir::solve::SizedTraitKind;
pub use rustc_type_ir::*;
#[allow(hidden_glob_reexports, unused_imports)]
use rustc_type_ir::{InferCtxtLike, Interner};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, trace};
pub use vtable::*;
use {rustc_ast as ast, rustc_hir as hir};
@@ -2256,6 +2256,10 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
typetree_from_ty_inner(tcx, ty, 0, &mut visited)
}
+/// Maximum recursion depth for TypeTree generation to prevent stack overflow
+/// from pathological deeply nested types. Combined with cycle detection.
+const MAX_TYPETREE_DEPTH: usize = 6;
+
/// Internal recursive function for TypeTree generation with cycle detection and depth limiting.
fn typetree_from_ty_inner<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -2263,19 +2267,8 @@ fn typetree_from_ty_inner<'tcx>(
depth: usize,
visited: &mut Vec>,
) -> TypeTree {
- #[cfg(llvm_enzyme)]
- {
- unsafe extern "C" {
- fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint;
- }
- let max_depth = unsafe { EnzymeGetMaxTypeDepth() } as usize;
- if depth > max_depth {
- return TypeTree::new();
- }
- }
-
- #[cfg(not(llvm_enzyme))]
- if depth > 6 {
+ if depth >= MAX_TYPETREE_DEPTH {
+ trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty);
return TypeTree::new();
}
diff --git a/src/llvm-project b/src/llvm-project
index 2a22c801439..333793696b0 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 2a22c8014390bdf387d8ed26005fee3187fb98bd
+Subproject commit 333793696b0a08002acac6af983adc7a5233fc56
diff --git a/src/tools/cargo b/src/tools/cargo
index a4bd03c92d3..966f94733bb 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit a4bd03c92d3b977909953d06cc45e263bd7ca7d8
+Subproject commit 966f94733bbc94ca51ff9f1e4c49ad250ebbdc50
--
cgit 1.4.1-3-g733a5
From 9daa026cadca6de0d932ddb6f6ddbfa5411a25e3 Mon Sep 17 00:00:00 2001
From: Zalathar
Date: Fri, 19 Sep 2025 16:56:28 +1000
Subject: Use `LLVMDIBuilder(CreateExpression|InsertDeclareRecordAtEnd)`
---
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 15 +++++++------
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 27 +++++++++++++++---------
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 12 -----------
3 files changed, 26 insertions(+), 28 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 126082aa3aa..dc36ed17875 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -191,18 +191,21 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
addr_ops.push((fragment.end - fragment.start).bits() as u64);
}
+ let di_builder = DIB(self.cx());
+ let addr_expr = unsafe {
+ llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
+ };
unsafe {
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
- llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
- DIB(self.cx()),
+ llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
+ di_builder,
variable_alloca,
dbg_var,
- addr_ops.as_ptr(),
- addr_ops.len() as c_uint,
+ addr_expr,
dbg_loc,
self.llbb(),
- );
- }
+ )
+ };
}
fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 290dbda77f6..11de4ed9653 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -806,6 +806,8 @@ unsafe extern "C" {
pub(crate) type Metadata;
pub(crate) type BasicBlock;
pub(crate) type Comdat;
+ /// `&'ll DbgRecord` represents `LLVMDbgRecordRef`.
+ pub(crate) type DbgRecord;
}
#[repr(C)]
pub(crate) struct Builder<'a>(InvariantOpaque<'a>);
@@ -2000,6 +2002,21 @@ unsafe extern "C" {
Data: *const Option<&'ll Metadata>,
NumElements: size_t,
) -> &'ll Metadata;
+
+ pub(crate) fn LLVMDIBuilderCreateExpression<'ll>(
+ Builder: &DIBuilder<'ll>,
+ Addr: *const u64,
+ Length: size_t,
+ ) -> &'ll Metadata;
+
+ pub(crate) fn LLVMDIBuilderInsertDeclareRecordAtEnd<'ll>(
+ Builder: &DIBuilder<'ll>,
+ Storage: &'ll Value,
+ VarInfo: &'ll Metadata,
+ Expr: &'ll Metadata,
+ DebugLoc: &'ll Metadata,
+ Block: &'ll BasicBlock,
+ ) -> &'ll DbgRecord;
}
#[link(name = "llvm-wrapper", kind = "static")]
@@ -2381,16 +2398,6 @@ unsafe extern "C" {
AlignInBits: u32,
) -> &'a DIVariable;
- pub(crate) fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>(
- Builder: &DIBuilder<'a>,
- Val: &'a Value,
- VarInfo: &'a DIVariable,
- AddrOps: *const u64,
- AddrOpsCount: c_uint,
- DL: &'a DILocation,
- InsertAtEnd: &'a BasicBlock,
- );
-
pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b7878692176..fc79cb9d473 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1142,18 +1142,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
}
}
-extern "C" void
-LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
- LLVMMetadataRef VarInfo, uint64_t *AddrOps,
- unsigned AddrOpsCount, LLVMMetadataRef DL,
- LLVMBasicBlockRef InsertAtEnd) {
- unwrap(Builder)->insertDeclare(
- unwrap(V), unwrap(VarInfo),
- unwrap(Builder)->createExpression(
- llvm::ArrayRef(AddrOps, AddrOpsCount)),
- DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd));
-}
-
extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
size_t NameLen, const uint64_t Value[2],
--
cgit 1.4.1-3-g733a5
From e39e5a0d157a56680cdc10a77551af225b797787 Mon Sep 17 00:00:00 2001
From: Zalathar
Date: Fri, 19 Sep 2025 16:14:35 +1000
Subject: Use `LLVMDIBuilderCreate(Auto|Parameter)Variable`
---
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 58 ++++++++++++------------
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 43 +++++++++++-------
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 18 --------
3 files changed, 57 insertions(+), 62 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index dc36ed17875..66b963436af 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -52,15 +52,6 @@ mod utils;
use self::create_scope_map::compute_mir_scopes;
pub(crate) use self::metadata::build_global_var_di_node;
-// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were
-// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp`
-// to decide which C++ API to call. Instead, we should just have two separate
-// FFI functions and choose the correct one on the Rust side.
-#[allow(non_upper_case_globals)]
-const DW_TAG_auto_variable: c_uint = 0x100;
-#[allow(non_upper_case_globals)]
-const DW_TAG_arg_variable: c_uint = 0x101;
-
/// A context object for maintaining all state needed by the debuginfo module.
pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
llmod: &'ll llvm::Module,
@@ -633,28 +624,39 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
let type_metadata = spanned_type_di_node(self, variable_type, span);
- let (argument_index, dwarf_tag) = match variable_kind {
- ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
- LocalVariable => (0, DW_TAG_auto_variable),
- };
let align = self.align_of(variable_type);
let name = variable_name.as_str();
- unsafe {
- llvm::LLVMRustDIBuilderCreateVariable(
- DIB(self),
- dwarf_tag,
- scope_metadata,
- name.as_c_char_ptr(),
- name.len(),
- file_metadata,
- loc.line,
- type_metadata,
- true,
- DIFlags::FlagZero,
- argument_index,
- align.bits() as u32,
- )
+
+ match variable_kind {
+ ArgumentVariable(arg_index) => unsafe {
+ llvm::LLVMDIBuilderCreateParameterVariable(
+ DIB(self),
+ scope_metadata,
+ name.as_ptr(),
+ name.len(),
+ arg_index as c_uint,
+ file_metadata,
+ loc.line,
+ type_metadata,
+ llvm::Bool::TRUE, // (preserve descriptor during optimizations)
+ DIFlags::FlagZero,
+ )
+ },
+ LocalVariable => unsafe {
+ llvm::LLVMDIBuilderCreateAutoVariable(
+ DIB(self),
+ scope_metadata,
+ name.as_ptr(),
+ name.len(),
+ file_metadata,
+ loc.line,
+ type_metadata,
+ llvm::Bool::TRUE, // (preserve descriptor during optimizations)
+ DIFlags::FlagZero,
+ align.bits() as u32,
+ )
+ },
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 11de4ed9653..b0388594f27 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -26,7 +26,7 @@ use super::RustString;
use super::debuginfo::{
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram,
- DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
+ DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind,
};
use crate::llvm;
@@ -2017,6 +2017,32 @@ unsafe extern "C" {
DebugLoc: &'ll Metadata,
Block: &'ll BasicBlock,
) -> &'ll DbgRecord;
+
+ pub(crate) fn LLVMDIBuilderCreateAutoVariable<'ll>(
+ Builder: &DIBuilder<'ll>,
+ Scope: &'ll Metadata,
+ Name: *const c_uchar, // See "PTR_LEN_STR".
+ NameLen: size_t,
+ File: &'ll Metadata,
+ LineNo: c_uint,
+ Ty: &'ll Metadata,
+ AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations."
+ Flags: DIFlags,
+ AlignInBits: u32,
+ ) -> &'ll Metadata;
+
+ pub(crate) fn LLVMDIBuilderCreateParameterVariable<'ll>(
+ Builder: &DIBuilder<'ll>,
+ Scope: &'ll Metadata,
+ Name: *const c_uchar, // See "PTR_LEN_STR".
+ NameLen: size_t,
+ ArgNo: c_uint,
+ File: &'ll Metadata,
+ LineNo: c_uint,
+ Ty: &'ll Metadata,
+ AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations."
+ Flags: DIFlags,
+ ) -> &'ll Metadata;
}
#[link(name = "llvm-wrapper", kind = "static")]
@@ -2383,21 +2409,6 @@ unsafe extern "C" {
AlignInBits: u32,
) -> &'a DIGlobalVariableExpression;
- pub(crate) fn LLVMRustDIBuilderCreateVariable<'a>(
- Builder: &DIBuilder<'a>,
- Tag: c_uint,
- Scope: &'a DIDescriptor,
- Name: *const c_char,
- NameLen: size_t,
- File: &'a DIFile,
- LineNo: c_uint,
- Ty: &'a DIType,
- AlwaysPreserve: bool,
- Flags: DIFlags,
- ArgNo: c_uint,
- AlignInBits: u32,
- ) -> &'a DIVariable;
-
pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index fc79cb9d473..c7fa26f18e1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1124,24 +1124,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
return wrap(VarExpr);
}
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
- LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope,
- const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo,
- LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo,
- uint32_t AlignInBits) {
- if (Tag == 0x100) { // DW_TAG_auto_variable
- return wrap(unwrap(Builder)->createAutoVariable(
- unwrapDI(Scope), StringRef(Name, NameLen),
- unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve,
- fromRust(Flags), AlignInBits));
- } else {
- return wrap(unwrap(Builder)->createParameterVariable(
- unwrapDI(Scope), StringRef(Name, NameLen), ArgNo,
- unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve,
- fromRust(Flags)));
- }
-}
-
extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
size_t NameLen, const uint64_t Value[2],
--
cgit 1.4.1-3-g733a5
From 272d336f0f89610bc18bc276b5f89dc163c69d24 Mon Sep 17 00:00:00 2001
From: Zalathar
Date: Fri, 19 Sep 2025 17:25:16 +1000
Subject: Remove some unnecessary `as u64` casts
In each of these casts, the LHS is already `u64`.
---
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 66b963436af..af64e4ebed0 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -165,21 +165,21 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
if direct_offset.bytes() > 0 {
addr_ops.push(DW_OP_plus_uconst);
- addr_ops.push(direct_offset.bytes() as u64);
+ addr_ops.push(direct_offset.bytes());
}
for &offset in indirect_offsets {
addr_ops.push(DW_OP_deref);
if offset.bytes() > 0 {
addr_ops.push(DW_OP_plus_uconst);
- addr_ops.push(offset.bytes() as u64);
+ addr_ops.push(offset.bytes());
}
}
if let Some(fragment) = fragment {
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
// offset and size, both of them in bits.
addr_ops.push(DW_OP_LLVM_fragment);
- addr_ops.push(fragment.start.bits() as u64);
- addr_ops.push((fragment.end - fragment.start).bits() as u64);
+ addr_ops.push(fragment.start.bits());
+ addr_ops.push((fragment.end - fragment.start).bits());
}
let di_builder = DIB(self.cx());
--
cgit 1.4.1-3-g733a5
From 9acc63a48c8206cfe2c2d272600d538983308657 Mon Sep 17 00:00:00 2001
From: Jana Dönszelmann
Date: Wed, 17 Sep 2025 22:29:49 -0700
Subject: port `#[debugger_visualizer]` to the new attribute system
---
.../rustc_attr_parsing/src/attributes/debugger.rs | 60 +++++++++++
compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 +
compiler/rustc_attr_parsing/src/context.rs | 2 +
compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +-
compiler/rustc_codegen_ssa/src/base.rs | 4 +-
compiler/rustc_hir/src/attrs/data_structures.rs | 19 +++-
compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 +
.../rustc_middle/src/middle/debugger_visualizer.rs | 8 +-
compiler/rustc_passes/messages.ftl | 9 --
compiler/rustc_passes/src/check_attr.rs | 16 +--
compiler/rustc_passes/src/debugger_visualizer.rs | 113 ++++++++++-----------
compiler/rustc_passes/src/errors.rs | 17 ----
tests/ui/attributes/malformed-attrs.rs | 3 +-
tests/ui/attributes/malformed-attrs.stderr | 53 +++++-----
.../invalid/invalid-debugger-visualizer-option.rs | 2 +-
.../invalid-debugger-visualizer-option.stderr | 22 ++--
.../invalid/invalid-debugger-visualizer-target.rs | 3 +-
.../invalid-debugger-visualizer-target.stderr | 4 +-
18 files changed, 185 insertions(+), 154 deletions(-)
create mode 100644 compiler/rustc_attr_parsing/src/attributes/debugger.rs
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
new file mode 100644
index 00000000000..56ff10be426
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
@@ -0,0 +1,60 @@
+use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType};
+
+use super::prelude::*;
+
+pub(crate) struct DebuggerViualizerParser;
+
+impl CombineAttributeParser for DebuggerViualizerParser {
+ const PATH: &[Symbol] = &[sym::debugger_visualizer];
+ const ALLOWED_TARGETS: AllowedTargets =
+ AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
+ const TEMPLATE: AttributeTemplate = template!(
+ List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
+ "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
+ );
+
+ type Item = DebugVisualizer;
+ const CONVERT: ConvertFn = |v, _| AttributeKind::DebuggerVisualizer(v);
+
+ fn extend<'c>(
+ cx: &'c mut AcceptContext<'_, '_, S>,
+ args: &'c ArgParser<'_>,
+ ) -> impl IntoIterator- + 'c {
+ let Some(l) = args.list() else {
+ cx.expected_list(args.span().unwrap_or(cx.attr_span));
+ return None;
+ };
+ let Some(single) = l.single() else {
+ cx.expected_single_argument(l.span);
+ return None;
+ };
+ let Some(mi) = single.meta_item() else {
+ cx.expected_name_value(single.span(), None);
+ return None;
+ };
+ let path = mi.path().word_sym();
+ let visualizer_type = match path {
+ Some(sym::natvis_file) => DebuggerVisualizerType::Natvis,
+ Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter,
+ _ => {
+ cx.expected_specific_argument(
+ mi.path().span(),
+ &[sym::natvis_file, sym::gdb_script_file],
+ );
+ return None;
+ }
+ };
+
+ let Some(path) = mi.args().name_value() else {
+ cx.expected_name_value(single.span(), path);
+ return None;
+ };
+
+ let Some(path) = path.value_as_str() else {
+ cx.expected_string_literal(path.value_span, Some(path.value_as_lit()));
+ return None;
+ };
+
+ Some(DebugVisualizer { span: mi.span(), visualizer_type, path })
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 4ed13d239b9..8dbf4c0ef32 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -36,6 +36,7 @@ pub(crate) mod cfg_old;
pub(crate) mod codegen_attrs;
pub(crate) mod confusables;
pub(crate) mod crate_level;
+pub(crate) mod debugger;
pub(crate) mod deprecation;
pub(crate) mod dummy;
pub(crate) mod inline;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 4c32bb87a24..1f1f9d6d50e 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -28,6 +28,7 @@ use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
};
+use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -163,6 +164,7 @@ attribute_parsers!(
// tidy-alphabetical-start
Combine,
Combine,
+ Combine,
Combine,
Combine,
Combine,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 7a6dc008c7b..3081badb821 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -2,9 +2,9 @@
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
use rustc_codegen_ssa::traits::*;
+use rustc_hir::attrs::DebuggerVisualizerType;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
-use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
use rustc_session::config::{CrateType, DebugInfo};
use crate::builder::Builder;
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 68a2f43ec67..422b06350e1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
use rustc_data_structures::unord::UnordMap;
-use rustc_hir::attrs::OptimizeAttr;
+use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemId, Target};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
use rustc_middle::middle::lang_items;
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 8ab43ff2582..5a9e644f970 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -363,6 +363,20 @@ pub struct LinkEntry {
pub import_name_type: Option<(PeImportNameType, Span)>,
}
+#[derive(HashStable_Generic, PrintAttribute)]
+#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+pub enum DebuggerVisualizerType {
+ Natvis,
+ GdbPrettyPrinter,
+}
+
+#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
+pub struct DebugVisualizer {
+ pub span: Span,
+ pub visualizer_type: DebuggerVisualizerType,
+ pub path: Symbol,
+}
+
/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
@@ -485,7 +499,10 @@ pub enum AttributeKind {
/// Represents `#[custom_mir]`.
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
- ///Represents `#[rustc_deny_explicit_impl]`.
+ /// Represents `#[debugger_visualizer]`.
+ DebuggerVisualizer(ThinVec),
+
+ /// Represents `#[rustc_deny_explicit_impl]`.
DenyExplicitImpl(Span),
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 8e443405074..7112daa327e 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -37,6 +37,7 @@ impl AttributeKind {
Coverage(..) => No,
CrateName { .. } => No,
CustomMir(_, _, _) => Yes,
+ DebuggerVisualizer(..) => No,
DenyExplicitImpl(..) => No,
Deprecation { .. } => Yes,
DoNotImplementViaObject(..) => No,
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
index 5a811321f58..a7f0095dcdf 100644
--- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -1,15 +1,9 @@
use std::path::PathBuf;
use std::sync::Arc;
+use rustc_hir::attrs::DebuggerVisualizerType;
use rustc_macros::{Decodable, Encodable, HashStable};
-#[derive(HashStable)]
-#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
-pub enum DebuggerVisualizerType {
- Natvis,
- GdbPrettyPrinter,
-}
-
/// A single debugger visualizer file.
#[derive(HashStable)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 6cd68380e46..870e0a90b54 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -93,15 +93,6 @@ passes_dead_codes =
}
} never {$participle}
-passes_debug_visualizer_invalid =
- invalid argument
- .note_1 = expected: `natvis_file = "..."`
- .note_2 = OR
- .note_3 = expected: `gdb_script_file = "..."`
-
-passes_debug_visualizer_placement =
- attribute should be applied to a module
-
passes_debug_visualizer_unreadable =
couldn't read {$file}: {$error}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 94c9e71ce77..9f40e713e50 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -281,6 +281,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::ObjcClass { .. }
| AttributeKind::ObjcSelector { .. }
| AttributeKind::RustcCoherenceIsCore(..)
+ | AttributeKind::DebuggerVisualizer(..)
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
@@ -301,7 +302,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
&mut doc_aliases,
),
[sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
- [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
[sym::rustc_no_implicit_autorefs, ..] => {
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
}
@@ -1782,20 +1782,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
- /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
- fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
- // Here we only check that the #[debugger_visualizer] attribute is attached
- // to nothing other than a module. All other checks are done in the
- // `debugger_visualizer` query where they need to be done for decoding
- // anyway.
- match target {
- Target::Mod => {}
- _ => {
- self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
- }
- }
- }
-
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
/// (Allows proc_macro functions)
fn check_rustc_allow_const_fn_unstable(
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 7a7a8175e55..7211f3cf85b 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -1,67 +1,60 @@
//! Detecting usage of the `#[debugger_visualizer]` attribute.
-use rustc_ast::Attribute;
+use rustc_ast::ast::NodeId;
+use rustc_ast::{HasNodeId, ItemKind, ast};
+use rustc_attr_parsing::AttributeParser;
use rustc_expand::base::resolve_path;
-use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_hir::Attribute;
+use rustc_hir::attrs::{AttributeKind, DebugVisualizer};
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::query::{LocalCrate, Providers};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
-use rustc_span::sym;
+use rustc_span::{DUMMY_SP, Span, sym};
-use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
+use crate::errors::DebugVisualizerUnreadable;
impl DebuggerVisualizerCollector<'_> {
- fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
- if attr.has_name(sym::debugger_visualizer) {
- let Some(hints) = attr.meta_item_list() else {
- self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
- return;
- };
+ fn check_for_debugger_visualizer(
+ &mut self,
+ attrs: &[ast::Attribute],
+ span: Span,
+ node_id: NodeId,
+ ) {
+ if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
+ AttributeParser::parse_limited(
+ &self.sess,
+ attrs,
+ sym::debugger_visualizer,
+ span,
+ node_id,
+ None,
+ )
+ {
+ for DebugVisualizer { span, visualizer_type, path } in visualizers {
+ let file = match resolve_path(&self.sess, path.as_str(), span) {
+ Ok(file) => file,
+ Err(err) => {
+ err.emit();
+ return;
+ }
+ };
- let [hint] = hints.as_slice() else {
- self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
- return;
- };
-
- let Some(meta_item) = hint.meta_item() else {
- self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
- return;
- };
-
- let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
- {
- (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
- (Some(sym::gdb_script_file), Some(value)) => {
- (DebuggerVisualizerType::GdbPrettyPrinter, value)
- }
- (_, _) => {
- self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
- return;
- }
- };
-
- let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
- Ok(file) => file,
- Err(err) => {
- err.emit();
- return;
- }
- };
-
- match self.sess.source_map().load_binary_file(&file) {
- Ok((source, _)) => {
- self.visualizers.push(DebuggerVisualizerFile::new(
- source,
- visualizer_type,
- file,
- ));
- }
- Err(error) => {
- self.sess.dcx().emit_err(DebugVisualizerUnreadable {
- span: meta_item.span,
- file: &file,
- error,
- });
+ match self.sess.source_map().load_binary_file(&file) {
+ Ok((source, _)) => {
+ self.visualizers.push(DebuggerVisualizerFile::new(
+ source,
+ visualizer_type,
+ file,
+ ));
+ }
+ Err(error) => {
+ self.sess.dcx().emit_err(DebugVisualizerUnreadable {
+ span,
+ file: &file,
+ error,
+ });
+ }
}
}
}
@@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> {
}
impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
- fn visit_attribute(&mut self, attr: &'ast Attribute) {
- self.check_for_debugger_visualizer(attr);
- rustc_ast::visit::walk_attribute(self, attr);
+ fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
+ if let ItemKind::Mod(..) = item.kind {
+ self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id());
+ }
+ rustc_ast::visit::walk_item(self, item);
+ }
+ fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
+ self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id);
+ rustc_ast::visit::walk_crate(self, krate);
}
}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index cd8935f6b2f..cfd6b9e6dff 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -475,23 +475,6 @@ pub(crate) struct MacroOnlyAttribute {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(passes_debug_visualizer_placement)]
-pub(crate) struct DebugVisualizerPlacement {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_debug_visualizer_invalid)]
-#[note(passes_note_1)]
-#[note(passes_note_2)]
-#[note(passes_note_3)]
-pub(crate) struct DebugVisualizerInvalid {
- #[primary_span]
- pub span: Span,
-}
-
#[derive(Diagnostic)]
#[diag(passes_debug_visualizer_unreadable)]
pub(crate) struct DebugVisualizerUnreadable<'a> {
diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs
index e30479b03b1..820484aa015 100644
--- a/tests/ui/attributes/malformed-attrs.rs
+++ b/tests/ui/attributes/malformed-attrs.rs
@@ -185,8 +185,7 @@ extern "C" {
#[forbid]
//~^ ERROR malformed
#[debugger_visualizer]
-//~^ ERROR invalid argument
-//~| ERROR malformed `debugger_visualizer` attribute input
+//~^ ERROR malformed `debugger_visualizer` attribute input
#[automatically_derived = 18]
//~^ ERROR malformed
mod yooo {
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 246029ecf80..70ab3fb13c4 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -22,7 +22,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
| ++++++++++++++++++++++++++++++++++++++++++++
error[E0463]: can't find crate for `wloop`
- --> $DIR/malformed-attrs.rs:210:1
+ --> $DIR/malformed-attrs.rs:209:1
|
LL | extern crate wloop;
| ^^^^^^^^^^^^^^^^^^^ can't find crate
@@ -156,22 +156,14 @@ LL | #[forbid(lint1, lint2, ...)]
LL | #[forbid(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
-error: malformed `debugger_visualizer` attribute input
- --> $DIR/malformed-attrs.rs:187:1
- |
-LL | #[debugger_visualizer]
- | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
- |
- = note: for more information, visit
-
error: malformed `thread_local` attribute input
- --> $DIR/malformed-attrs.rs:202:1
+ --> $DIR/malformed-attrs.rs:201:1
|
LL | #[thread_local()]
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]`
error: malformed `no_link` attribute input
- --> $DIR/malformed-attrs.rs:206:1
+ --> $DIR/malformed-attrs.rs:205:1
|
LL | #[no_link()]
| ^^^^^^^^^^^^ help: must be of the form: `#[no_link]`
@@ -197,7 +189,7 @@ LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^
error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
- --> $DIR/malformed-attrs.rs:215:1
+ --> $DIR/malformed-attrs.rs:214:1
|
LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -226,16 +218,6 @@ LL | #[doc]
= note: for more information, see issue #57571
= note: for more information, visit
-error: invalid argument
- --> $DIR/malformed-attrs.rs:187:1
- |
-LL | #[debugger_visualizer]
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: expected: `natvis_file = "..."`
- = note: OR
- = note: expected: `gdb_script_file = "..."`
-
error[E0539]: malformed `export_name` attribute input
--> $DIR/malformed-attrs.rs:29:1
|
@@ -685,8 +667,19 @@ LL | #[linkage = "external"]
| ++++++++++++
= and 5 other candidates
+error[E0539]: malformed `debugger_visualizer` attribute input
+ --> $DIR/malformed-attrs.rs:187:1
+ |
+LL | #[debugger_visualizer]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected this to be a list
+ | help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
+ |
+ = note: for more information, visit
+
error[E0565]: malformed `automatically_derived` attribute input
- --> $DIR/malformed-attrs.rs:190:1
+ --> $DIR/malformed-attrs.rs:189:1
|
LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^----^
@@ -695,7 +688,7 @@ LL | #[automatically_derived = 18]
| help: must be of the form: `#[automatically_derived]`
error[E0565]: malformed `non_exhaustive` attribute input
- --> $DIR/malformed-attrs.rs:196:1
+ --> $DIR/malformed-attrs.rs:195:1
|
LL | #[non_exhaustive = 1]
| ^^^^^^^^^^^^^^^^^---^
@@ -704,19 +697,19 @@ LL | #[non_exhaustive = 1]
| help: must be of the form: `#[non_exhaustive]`
error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]`
- --> $DIR/malformed-attrs.rs:208:1
+ --> $DIR/malformed-attrs.rs:207:1
|
LL | #[macro_use = 1]
| ^^^^^^^^^^^^^^^^
error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
- --> $DIR/malformed-attrs.rs:213:1
+ --> $DIR/malformed-attrs.rs:212:1
|
LL | #[macro_export = 18]
| ^^^^^^^^^^^^^^^^^^^^
error[E0565]: malformed `allow_internal_unsafe` attribute input
- --> $DIR/malformed-attrs.rs:215:1
+ --> $DIR/malformed-attrs.rs:214:1
|
LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^---^
@@ -800,7 +793,7 @@ LL | #[ignore()]
= note: for more information, see issue #57571
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
- --> $DIR/malformed-attrs.rs:222:1
+ --> $DIR/malformed-attrs.rs:221:1
|
LL | #[ignore = 1]
| ^^^^^^^^^^^^^
@@ -819,7 +812,7 @@ LL | #[coroutine = 63] || {}
= note: expected unit type `()`
found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}`
-error: aborting due to 77 previous errors; 3 warnings emitted
+error: aborting due to 76 previous errors; 3 warnings emitted
Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805.
For more information about an error, try `rustc --explain E0308`.
@@ -871,7 +864,7 @@ LL | #[ignore()]
Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
- --> $DIR/malformed-attrs.rs:222:1
+ --> $DIR/malformed-attrs.rs:221:1
|
LL | #[ignore = 1]
| ^^^^^^^^^^^^^
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.rs b/tests/ui/invalid/invalid-debugger-visualizer-option.rs
index 0f1cf15a687..166962866dc 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-option.rs
+++ b/tests/ui/invalid/invalid-debugger-visualizer-option.rs
@@ -1,6 +1,6 @@
//@ normalize-stderr: "foo.random:.*\(" -> "foo.random: $$FILE_NOT_FOUND_MSG ("
//@ normalize-stderr: "os error \d+" -> "os error $$FILE_NOT_FOUND_CODE"
-#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR invalid argument
+#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR malformed `debugger_visualizer` attribute input
#![debugger_visualizer(natvis_file = "../foo.random")] //~ ERROR
fn main() {}
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr b/tests/ui/invalid/invalid-debugger-visualizer-option.stderr
index 6fbb4d641e6..e877e39d8f1 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr
+++ b/tests/ui/invalid/invalid-debugger-visualizer-option.stderr
@@ -1,18 +1,20 @@
-error: invalid argument
- --> $DIR/invalid-debugger-visualizer-option.rs:4:24
- |
-LL | #![debugger_visualizer(random_file = "../foo.random")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: expected: `natvis_file = "..."`
- = note: OR
- = note: expected: `gdb_script_file = "..."`
-
error: couldn't read $DIR/../foo.random: $FILE_NOT_FOUND_MSG (os error $FILE_NOT_FOUND_CODE)
--> $DIR/invalid-debugger-visualizer-option.rs:5:24
|
LL | #![debugger_visualizer(natvis_file = "../foo.random")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0539]: malformed `debugger_visualizer` attribute input
+ --> $DIR/invalid-debugger-visualizer-option.rs:4:1
+ |
+LL | #![debugger_visualizer(random_file = "../foo.random")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | valid arguments are `natvis_file` or `gdb_script_file`
+ | help: must be of the form: `#![debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
+ |
+ = note: for more information, visit
+
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.rs b/tests/ui/invalid/invalid-debugger-visualizer-target.rs
index 1efb9555c24..48b04153214 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-target.rs
+++ b/tests/ui/invalid/invalid-debugger-visualizer-target.rs
@@ -1,2 +1,3 @@
-#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module
+#[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
+//~^ ERROR `#[debugger_visualizer]` attribute cannot be used on functions
fn main() {}
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr
index 1df34532533..629af94c5ef 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr
+++ b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr
@@ -1,8 +1,10 @@
-error: attribute should be applied to a module
+error: `#[debugger_visualizer]` attribute cannot be used on functions
--> $DIR/invalid-debugger-visualizer-target.rs:1:1
|
LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: `#[debugger_visualizer]` can be applied to modules and crates
error: aborting due to 1 previous error
--
cgit 1.4.1-3-g733a5
From f5c6c9542ecfab74e654f9b7f1150d486560ae43 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Tue, 16 Sep 2025 02:23:24 -0400
Subject: Add an attribute to check the number of lanes in a SIMD vector after
monomorphization
Unify zero-length and oversized SIMD errors
---
.../src/attributes/crate_level.rs | 36 ---------------------
.../src/attributes/rustc_internal.rs | 18 +++++++++++
compiler/rustc_attr_parsing/src/attributes/util.rs | 37 +++++++++++++++++++++-
compiler/rustc_attr_parsing/src/context.rs | 3 +-
compiler/rustc_codegen_cranelift/src/common.rs | 9 ++++--
compiler/rustc_codegen_cranelift/src/global_asm.rs | 5 ++-
compiler/rustc_codegen_gcc/src/context.rs | 9 ++++--
compiler/rustc_codegen_llvm/src/context.rs | 11 +++++--
compiler/rustc_feature/src/builtin_attrs.rs | 6 ++++
compiler/rustc_hir/src/attrs/data_structures.rs | 3 ++
compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 +
.../rustc_hir_analysis/src/hir_ty_lowering/cmse.rs | 1 +
compiler/rustc_middle/messages.ftl | 6 ++++
compiler/rustc_middle/src/error.rs | 6 ++++
compiler/rustc_middle/src/ty/layout.rs | 26 +++++++++++++++
compiler/rustc_passes/src/check_attr.rs | 1 +
compiler/rustc_span/src/symbol.rs | 1 +
compiler/rustc_transmute/src/layout/tree.rs | 1 +
compiler/rustc_ty_utils/src/errors.rs | 13 --------
compiler/rustc_ty_utils/src/layout.rs | 26 ++++++++++++---
src/librustdoc/html/templates/type_layout.html | 5 +++
tests/ui/simd/auxiliary/simd-lane-limit.rs | 5 +++
tests/ui/simd/monomorphize-too-long.rs | 4 +--
tests/ui/simd/monomorphize-too-long.stderr | 6 +++-
tests/ui/simd/monomorphize-zero-length.rs | 4 +--
tests/ui/simd/monomorphize-zero-length.stderr | 6 +++-
tests/ui/simd/simd-lane-limit-err-npow2.rs | 12 +++++++
tests/ui/simd/simd-lane-limit-err-npow2.stderr | 8 +++++
tests/ui/simd/simd-lane-limit-err.rs | 11 +++++++
tests/ui/simd/simd-lane-limit-err.stderr | 8 +++++
tests/ui/simd/simd-lane-limit-ok.rs | 14 ++++++++
.../ui/simd/type-generic-monomorphisation-empty.rs | 4 +--
.../type-generic-monomorphisation-empty.stderr | 6 +++-
.../type-generic-monomorphisation-oversized.rs | 5 ++-
.../type-generic-monomorphisation-oversized.stderr | 6 +++-
35 files changed, 245 insertions(+), 78 deletions(-)
create mode 100644 tests/ui/simd/auxiliary/simd-lane-limit.rs
create mode 100644 tests/ui/simd/simd-lane-limit-err-npow2.rs
create mode 100644 tests/ui/simd/simd-lane-limit-err-npow2.stderr
create mode 100644 tests/ui/simd/simd-lane-limit-err.rs
create mode 100644 tests/ui/simd/simd-lane-limit-err.stderr
create mode 100644 tests/ui/simd/simd-lane-limit-ok.rs
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 4611de44459..00edafecd9a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -1,40 +1,4 @@
-use std::num::IntErrorKind;
-
-use rustc_hir::limit::Limit;
-
use super::prelude::*;
-use crate::session_diagnostics::LimitInvalid;
-
-impl AcceptContext<'_, '_, S> {
- fn parse_limit_int(&self, nv: &NameValueParser) -> Option {
- let Some(limit) = nv.value_as_str() else {
- self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
- return None;
- };
-
- let error_str = match limit.as_str().parse() {
- Ok(i) => return Some(Limit::new(i)),
- Err(e) => match e.kind() {
- IntErrorKind::PosOverflow => "`limit` is too large",
- IntErrorKind::Empty => "`limit` must be a non-negative integer",
- IntErrorKind::InvalidDigit => "not a valid integer",
- IntErrorKind::NegOverflow => {
- panic!(
- "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
- )
- }
- IntErrorKind::Zero => {
- panic!("zero is a valid `limit` so should have returned Ok() when parsing")
- }
- kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
- },
- };
-
- self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
-
- None
- }
-}
pub(crate) struct CrateNameParser;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index a995549fc7c..cf2f5c6c790 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -49,3 +49,21 @@ impl SingleAttributeParser
for RustcObjectLifetimeDefaultParser {
Some(AttributeKind::RustcObjectLifetimeDefault)
}
}
+
+pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
+
+impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser {
+ const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
+ const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option {
+ let ArgParser::NameValue(nv) = args else {
+ cx.expected_name_value(cx.attr_span, None);
+ return None;
+ };
+ Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index 77e8c32e59d..62b72798e96 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -1,11 +1,15 @@
+use std::num::IntErrorKind;
+
use rustc_ast::LitKind;
use rustc_ast::attr::AttributeExt;
use rustc_feature::is_builtin_attr_name;
use rustc_hir::RustcVersion;
+use rustc_hir::limit::Limit;
use rustc_span::{Symbol, sym};
use crate::context::{AcceptContext, Stage};
-use crate::parser::ArgParser;
+use crate::parser::{ArgParser, NameValueParser};
+use crate::session_diagnostics::LimitInvalid;
/// Parse a rustc version number written inside string literal in an attribute,
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
@@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer(
};
Some(num.0)
}
+
+impl AcceptContext<'_, '_, S> {
+ pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option {
+ let Some(limit) = nv.value_as_str() else {
+ self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return None;
+ };
+
+ let error_str = match limit.as_str().parse() {
+ Ok(i) => return Some(Limit::new(i)),
+ Err(e) => match e.kind() {
+ IntErrorKind::PosOverflow => "`limit` is too large",
+ IntErrorKind::Empty => "`limit` must be a non-negative integer",
+ IntErrorKind::InvalidDigit => "not a valid integer",
+ IntErrorKind::NegOverflow => {
+ panic!(
+ "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
+ )
+ }
+ IntErrorKind::Zero => {
+ panic!("zero is a valid `limit` so should have returned Ok() when parsing")
+ }
+ kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
+ },
+ };
+
+ self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
+
+ None
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index d7998048be5..72fe269b135 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -53,7 +53,7 @@ use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
- RustcObjectLifetimeDefaultParser,
+ RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
use crate::attributes::stability::{
@@ -195,6 +195,7 @@ attribute_parsers!(
Single,
Single,
Single,
+ Single,
Single,
Single,
Single,
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 2fbe5c02802..81b1814605a 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -439,7 +439,10 @@ pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::InvalidSimd { .. }
+ | LayoutError::ReferencesError(_) = err
+ {
self.0.sess.dcx().span_fatal(span, err.to_string())
} else {
self.0
@@ -458,7 +461,9 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
- if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+ if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
+ err
+ {
self.0.sess.dcx().emit_fatal(Spanned { span, node: err })
} else {
match fn_abi_request {
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index 203b443269f..1306c6aa517 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -42,7 +42,10 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::InvalidSimd { .. }
+ | LayoutError::ReferencesError(_) = err
+ {
self.tcx.sess.dcx().span_fatal(span, err.to_string())
} else {
self.tcx
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 665cf22ddba..9815fb07eaa 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -529,7 +529,10 @@ impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::InvalidSimd { .. }
+ | LayoutError::ReferencesError(_) = err
+ {
self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic()))
} else {
self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
@@ -545,7 +548,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
- if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+ if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
+ err
+ {
self.tcx.dcx().emit_fatal(respan(span, err))
} else {
match fn_abi_request {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index a69fa54a54a..e4528efaa37 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -991,7 +991,10 @@ impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> {
impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
- if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+ if let LayoutError::SizeOverflow(_)
+ | LayoutError::ReferencesError(_)
+ | LayoutError::InvalidSimd { .. } = err
+ {
self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() })
} else {
self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
@@ -1008,7 +1011,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
match err {
- FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => {
+ FnAbiError::Layout(
+ LayoutError::SizeOverflow(_)
+ | LayoutError::Cycle(_)
+ | LayoutError::InvalidSimd { .. },
+ ) => {
self.tcx.dcx().emit_fatal(Spanned { span, node: err });
}
_ => match fn_abi_request {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 129ab7eccb5..0d890b57de0 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1203,6 +1203,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in the standard library",
),
+ rustc_attr!(
+ rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing,
+ EncodeCrossCrate::Yes,
+ "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
+ for better error messages",
+ ),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes,
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index ea11a99efbc..80cb6417684 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -642,6 +642,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_object_lifetime_default]`.
RustcObjectLifetimeDefault,
+ /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
+ RustcSimdMonomorphizeLaneLimit(Limit),
+
/// Represents `#[sanitize]`
///
/// the on set and off set are distjoint since there's a third option: unset.
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 55521c15854..968ea668efe 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -85,6 +85,7 @@ impl AttributeKind {
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,
+ RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
Sanitize { .. } => No,
ShouldPanic { .. } => No,
SkipDuringMethodDispatch { .. } => No,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 5088c63702e..76b0ce985f0 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -213,6 +213,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
}
Unknown(..)
| SizeOverflow(..)
+ | InvalidSimd { .. }
| NormalizationFailure(..)
| ReferencesError(..)
| Cycle(..) => {
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 279ab9a9d8f..82f3df8da3b 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -98,6 +98,12 @@ middle_layout_references_error =
middle_layout_size_overflow =
values of the type `{$ty}` are too big for the target architecture
+middle_layout_simd_too_many =
+ the SIMD type `{$ty}` has more elements than the limit {$max_lanes}
+
+middle_layout_simd_zero_length =
+ the SIMD type `{$ty}` has zero elements
+
middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
middle_layout_unknown =
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index dad402ec696..e15da827bda 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -141,6 +141,12 @@ pub enum LayoutError<'tcx> {
#[diag(middle_layout_size_overflow)]
Overflow { ty: Ty<'tcx> },
+ #[diag(middle_layout_simd_too_many)]
+ SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 },
+
+ #[diag(middle_layout_simd_zero_length)]
+ SimdZeroLength { ty: Ty<'tcx> },
+
#[diag(middle_layout_normalization_failure)]
NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 2114d080dfa..47e561d9d3c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -217,6 +217,15 @@ impl fmt::Display for ValidityRequirement {
}
}
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
+pub enum SimdLayoutError {
+ /// The vector has 0 lanes.
+ ZeroLength,
+ /// The vector has more lanes than supported or permitted by
+ /// #\[rustc_simd_monomorphize_lane_limit\].
+ TooManyLanes(u64),
+}
+
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
pub enum LayoutError<'tcx> {
/// A type doesn't have a sensible layout.
@@ -229,6 +238,8 @@ pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
/// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
SizeOverflow(Ty<'tcx>),
+ /// A SIMD vector has invalid layout, such as zero-length or too many lanes.
+ InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError },
/// The layout can vary due to a generic parameter.
///
/// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
@@ -256,6 +267,10 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(_) => middle_layout_unknown,
SizeOverflow(_) => middle_layout_size_overflow,
+ InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => {
+ middle_layout_simd_too_many
+ }
+ InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length,
TooGeneric(_) => middle_layout_too_generic,
NormalizationFailure(_, _) => middle_layout_normalization_failure,
Cycle(_) => middle_layout_cycle,
@@ -270,6 +285,10 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(ty) => E::Unknown { ty },
SizeOverflow(ty) => E::Overflow { ty },
+ InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
+ E::SimdTooManyLanes { ty, max_lanes }
+ }
+ InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty },
TooGeneric(ty) => E::TooGeneric { ty },
NormalizationFailure(ty, e) => {
E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
@@ -292,6 +311,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{ty}` are too big for the target architecture")
}
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
+ write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}")
+ }
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => {
+ write!(f, "the SIMD type `{ty}` has zero elements")
+ }
LayoutError::NormalizationFailure(t, e) => write!(
f,
"unable to determine layout for `{}` because `{}` cannot be normalized",
@@ -373,6 +398,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
e @ LayoutError::Cycle(_)
| e @ LayoutError::Unknown(_)
| e @ LayoutError::SizeOverflow(_)
+ | e @ LayoutError::InvalidSimd { .. }
| e @ LayoutError::NormalizationFailure(..)
| e @ LayoutError::ReferencesError(_),
) => return Err(e),
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2562d2e0b83..cabf2819741 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -254,6 +254,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::MacroEscape( .. )
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
+ | AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
| AttributeKind::ExportStable
| AttributeKind::FfiConst(..)
| AttributeKind::UnstableFeatureBound(..)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cdb0b5b58da..92a1fad4755 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1937,6 +1937,7 @@ symbols! {
rustc_regions,
rustc_reservation_impl,
rustc_serialize,
+ rustc_simd_monomorphize_lane_limit,
rustc_skip_during_method_dispatch,
rustc_specialization_trait,
rustc_std_internal_symbol,
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index d7ea26a2ab1..a02e8ecf613 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -279,6 +279,7 @@ pub(crate) mod rustc {
LayoutError::Unknown(..)
| LayoutError::ReferencesError(..)
| LayoutError::TooGeneric(..)
+ | LayoutError::InvalidSimd { .. }
| LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
LayoutError::SizeOverflow(..) => Self::SizeOverflow,
LayoutError::Cycle(err) => Self::TypeError(*err),
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 0298e7e0e95..f92c405242c 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -78,19 +78,6 @@ pub(crate) struct UnexpectedFnPtrAssociatedItem {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(ty_utils_zero_length_simd_type)]
-pub(crate) struct ZeroLengthSimdType<'tcx> {
- pub ty: Ty<'tcx>,
-}
-
-#[derive(Diagnostic)]
-#[diag(ty_utils_oversized_simd_type)]
-pub(crate) struct OversizedSimdType<'tcx> {
- pub ty: Ty<'tcx>,
- pub max_lanes: u64,
-}
-
#[derive(Diagnostic)]
#[diag(ty_utils_non_primitive_simd_type)]
pub(crate) struct NonPrimitiveSimdType<'tcx> {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 79f7e228e2a..5c4451ce264 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -7,11 +7,13 @@ use rustc_abi::{
VariantIdx, Variants, WrappingRange,
};
use rustc_hashes::Hash64;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{
- FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
+ FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
@@ -22,7 +24,7 @@ use rustc_span::{Symbol, sym};
use tracing::{debug, instrument};
use {rustc_abi as abi, rustc_hir as hir};
-use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType};
+use crate::errors::NonPrimitiveSimdType;
mod invariant;
@@ -120,11 +122,11 @@ fn map_error<'tcx>(
}
LayoutCalculatorError::ZeroLengthSimdType => {
// Can't be caught in typeck if the array length is generic.
- cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty })
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
}
LayoutCalculatorError::OversizedSimdType { max_lanes } => {
// Can't be caught in typeck if the array length is generic.
- cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes })
+ LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) }
}
LayoutCalculatorError::NonPrimitiveSimdType(field) => {
// This error isn't caught in typeck, e.g., if
@@ -561,6 +563,22 @@ fn layout_of_uncached<'tcx>(
let e_ly = cx.layout_of(e_ty)?;
+ // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit
+ if let Some(limit) = find_attr!(
+ tcx.get_all_attrs(def.did()),
+ AttributeKind::RustcSimdMonomorphizeLaneLimit(limit) => limit
+ ) {
+ if !limit.value_within_limit(e_len as usize) {
+ return Err(map_error(
+ &cx,
+ ty,
+ rustc_abi::LayoutCalculatorError::OversizedSimdType {
+ max_lanes: limit.0 as u64,
+ },
+ ));
+ }
+ }
+
map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
}
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 0034552bdd3..49153d58fe9 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -65,5 +65,10 @@
Note: Encountered an error during type layout; {#+ #}
the type's layout depended on the type's layout itself. {# #}
+ {% when Err(LayoutError::InvalidSimd {..}) %}
+ {# #}
+ Note: Encountered an error during type layout; {#+ #}
+ the vector type had zero elements or too many elements. {# #}
+
{% endmatch %}
{# #}
diff --git a/tests/ui/simd/auxiliary/simd-lane-limit.rs b/tests/ui/simd/auxiliary/simd-lane-limit.rs
new file mode 100644
index 00000000000..dde6b880c62
--- /dev/null
+++ b/tests/ui/simd/auxiliary/simd-lane-limit.rs
@@ -0,0 +1,5 @@
+#![feature(rustc_attrs, repr_simd)]
+
+#[repr(simd, packed)]
+#[rustc_simd_monomorphize_lane_limit = "8"]
+pub struct Simd(pub [T; N]);
diff --git a/tests/ui/simd/monomorphize-too-long.rs b/tests/ui/simd/monomorphize-too-long.rs
index 4fac987b0b5..9c837415191 100644
--- a/tests/ui/simd/monomorphize-too-long.rs
+++ b/tests/ui/simd/monomorphize-too-long.rs
@@ -6,7 +6,5 @@
struct Simd([T; N]);
fn main() {
- let _too_big = Simd([1_u16; 54321]);
+ let _too_big = Simd([1_u16; 54321]); //~ ERROR the SIMD type `Simd` has more elements than the limit 32768
}
-
-//~? ERROR monomorphising SIMD type `Simd` of length greater than 32768
diff --git a/tests/ui/simd/monomorphize-too-long.stderr b/tests/ui/simd/monomorphize-too-long.stderr
index 978eef307ab..71bc78ef5c9 100644
--- a/tests/ui/simd/monomorphize-too-long.stderr
+++ b/tests/ui/simd/monomorphize-too-long.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd` of length greater than 32768
+error: the SIMD type `Simd` has more elements than the limit 32768
+ --> $DIR/monomorphize-too-long.rs:9:9
+ |
+LL | let _too_big = Simd([1_u16; 54321]);
+ | ^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/simd/monomorphize-zero-length.rs b/tests/ui/simd/monomorphize-zero-length.rs
index d38870c572d..f956197a61c 100644
--- a/tests/ui/simd/monomorphize-zero-length.rs
+++ b/tests/ui/simd/monomorphize-zero-length.rs
@@ -6,7 +6,5 @@
struct Simd([T; N]);
fn main() {
- let _empty = Simd([1.0; 0]);
+ let _empty = Simd([1.0; 0]); //~ ERROR the SIMD type `Simd` has zero elements
}
-
-//~? ERROR monomorphising SIMD type `Simd` of zero length
diff --git a/tests/ui/simd/monomorphize-zero-length.stderr b/tests/ui/simd/monomorphize-zero-length.stderr
index 738c20fe51a..66f26d95c9d 100644
--- a/tests/ui/simd/monomorphize-zero-length.stderr
+++ b/tests/ui/simd/monomorphize-zero-length.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd` of zero length
+error: the SIMD type `Simd` has zero elements
+ --> $DIR/monomorphize-zero-length.rs:9:9
+ |
+LL | let _empty = Simd([1.0; 0]);
+ | ^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.rs b/tests/ui/simd/simd-lane-limit-err-npow2.rs
new file mode 100644
index 00000000000..d5c5c92e953
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err-npow2.rs
@@ -0,0 +1,12 @@
+//@ build-fail
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+ // test non-power-of-two, since #[repr(simd, packed)] has unusual layout
+ let _x: Simd = Simd([0; 24]);
+ //~^ ERROR the SIMD type `simd::Simd` has more elements than the limit 8
+}
diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.stderr b/tests/ui/simd/simd-lane-limit-err-npow2.stderr
new file mode 100644
index 00000000000..fff26c4c1c1
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err-npow2.stderr
@@ -0,0 +1,8 @@
+error: the SIMD type `simd::Simd` has more elements than the limit 8
+ --> $DIR/simd-lane-limit-err-npow2.rs:10:9
+ |
+LL | let _x: Simd = Simd([0; 24]);
+ | ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/simd-lane-limit-err.rs b/tests/ui/simd/simd-lane-limit-err.rs
new file mode 100644
index 00000000000..00390bdbdaf
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err.rs
@@ -0,0 +1,11 @@
+//@ build-fail
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+ let _x: Simd = Simd([0; 16]);
+ //~^ ERROR the SIMD type `simd::Simd` has more elements than the limit 8
+}
diff --git a/tests/ui/simd/simd-lane-limit-err.stderr b/tests/ui/simd/simd-lane-limit-err.stderr
new file mode 100644
index 00000000000..3f2eaeda2d4
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err.stderr
@@ -0,0 +1,8 @@
+error: the SIMD type `simd::Simd` has more elements than the limit 8
+ --> $DIR/simd-lane-limit-err.rs:9:9
+ |
+LL | let _x: Simd = Simd([0; 16]);
+ | ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/simd-lane-limit-ok.rs b/tests/ui/simd/simd-lane-limit-ok.rs
new file mode 100644
index 00000000000..52fd3158440
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-ok.rs
@@ -0,0 +1,14 @@
+//@ build-pass
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+ let _x: Simd = Simd([0; 4]);
+ let _y: Simd = Simd([0; 8]);
+
+ // test non-power-of-two, since #[repr(simd, packed)] has unusual layout
+ let _z: Simd = Simd([0; 6]);
+}
diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.rs b/tests/ui/simd/type-generic-monomorphisation-empty.rs
index c08dc9fe3df..7c43b8914da 100644
--- a/tests/ui/simd/type-generic-monomorphisation-empty.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-empty.rs
@@ -6,7 +6,5 @@
struct Simd([f32; N]);
fn main() {
- let _ = Simd::<0>([]);
+ let _empty = Simd::<0>([]); //~ ERROR the SIMD type `Simd<0>` has zero elements
}
-
-//~? ERROR monomorphising SIMD type `Simd<0>` of zero length
diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.stderr b/tests/ui/simd/type-generic-monomorphisation-empty.stderr
index fc294607ae3..450db7e47db 100644
--- a/tests/ui/simd/type-generic-monomorphisation-empty.stderr
+++ b/tests/ui/simd/type-generic-monomorphisation-empty.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<0>` of zero length
+error: the SIMD type `Simd<0>` has zero elements
+ --> $DIR/type-generic-monomorphisation-empty.rs:9:9
+ |
+LL | let _empty = Simd::<0>([]);
+ | ^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.rs b/tests/ui/simd/type-generic-monomorphisation-oversized.rs
index efe3480317c..73a1f00e8c7 100644
--- a/tests/ui/simd/type-generic-monomorphisation-oversized.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-oversized.rs
@@ -6,7 +6,6 @@
struct Simd([f32; N]);
fn main() {
- let _ = Simd::<65536>([0.; 65536]);
+ let _x = Simd::<65536>([0.; 65536]);
+ //~^ ERROR the SIMD type `Simd<65536>` has more elements than the limit 32768
}
-
-//~? ERROR monomorphising SIMD type `Simd<65536>` of length greater than 32768
diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
index 39ff36799cc..0065049abd6 100644
--- a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
+++ b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<65536>` of length greater than 32768
+error: the SIMD type `Simd<65536>` has more elements than the limit 32768
+ --> $DIR/type-generic-monomorphisation-oversized.rs:9:9
+ |
+LL | let _x = Simd::<65536>([0.; 65536]);
+ | ^^
error: aborting due to 1 previous error
--
cgit 1.4.1-3-g733a5
From 60548ffaa3dafec019e52f39ab7a075d3f11e24e Mon Sep 17 00:00:00 2001
From: Caleb Zulawski
Date: Tue, 23 Sep 2025 22:14:25 -0400
Subject: Including spans in layout errors for all ADTs
---
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index dc3a84b6a15..7ecba13d727 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -469,8 +469,8 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id),
ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id),
ty::Adt(def, ..) => match def.adt_kind() {
- AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
- AdtKind::Union => build_union_type_di_node(cx, unique_type_id),
+ AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id, span),
+ AdtKind::Union => build_union_type_di_node(cx, unique_type_id, span),
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span),
},
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
@@ -1066,6 +1066,7 @@ fn visibility_di_flags<'ll, 'tcx>(
fn build_struct_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
+ span: Span,
) -> DINodeCreationResult<'ll> {
let struct_type = unique_type_id.expect_ty();
let ty::Adt(adt_def, _) = struct_type.kind() else {
@@ -1073,7 +1074,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
};
assert!(adt_def.is_struct());
let containing_scope = get_namespace_for_item(cx, adt_def.did());
- let struct_type_and_layout = cx.layout_of(struct_type);
+ let struct_type_and_layout = cx.spanned_layout_of(struct_type, span);
let variant_def = adt_def.non_enum_variant();
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
@@ -1266,6 +1267,7 @@ fn build_closure_env_di_node<'ll, 'tcx>(
fn build_union_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
+ span: Span,
) -> DINodeCreationResult<'ll> {
let union_type = unique_type_id.expect_ty();
let (union_def_id, variant_def) = match union_type.kind() {
@@ -1273,7 +1275,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
_ => bug!("build_union_type_di_node on a non-ADT"),
};
let containing_scope = get_namespace_for_item(cx, union_def_id);
- let union_ty_and_layout = cx.layout_of(union_type);
+ let union_ty_and_layout = cx.spanned_layout_of(union_type, span);
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(union_def_id)))
--
cgit 1.4.1-3-g733a5
From 85018f09f67bd54868fe12a4632bbd637a474853 Mon Sep 17 00:00:00 2001
From: Zalathar
Date: Thu, 25 Sep 2025 18:10:55 +1000
Subject: Use `LLVMDisposeTargetMachine`
---
compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 4 +---
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 ++-
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 4 ----
3 files changed, 3 insertions(+), 8 deletions(-)
(limited to 'compiler/rustc_codegen_llvm/src')
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index d5228f0e0de..903a882916e 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -95,8 +95,6 @@ impl Drop for OwnedTargetMachine {
// SAFETY: constructing ensures we have a valid pointer created by
// llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no
// double free or use after free.
- unsafe {
- llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr());
- }
+ unsafe { llvm::LLVMDisposeTargetMachine(self.tm_unique) };
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index fd972f371df..38a6a311954 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1053,6 +1053,8 @@ unsafe extern "C" {
SLen: c_uint,
) -> MetadataKindId;
+ pub(crate) fn LLVMDisposeTargetMachine(T: ptr::NonNull);
+
// Create modules.
pub(crate) fn LLVMModuleCreateWithNameInContext(
ModuleID: *const c_char,
@@ -2499,7 +2501,6 @@ unsafe extern "C" {
UseWasmEH: bool,
) -> *mut TargetMachine;
- pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
pub(crate) fn LLVMRustAddLibraryInfo<'a>(
PM: &PassManager<'a>,
M: &'a Module,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7518b40799b..013d68fa3e4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -359,10 +359,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
return wrap(TM);
}
-extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
- delete unwrap(TM);
-}
-
// Unfortunately, the LLVM C API doesn't provide a way to create the
// TargetLibraryInfo pass, so we use this method to do so.
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
--
cgit 1.4.1-3-g733a5