Repository: rust-lang/rust
Pull request #139308: add autodiff inline
Author: login: Shourya742
Labels: name: T-compiler
description: Relevant to the compiler team, which will review and decide on the PR/issue.
name: S-waiting-on-bors
description: Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
name: F-autodiff
description: `#![feature(autodiff)]`
Created: 2025-04-03T09:03:01Z | Merged: 2025-04-29T05:35:38Z

closes: #138920

r? @ZuseZ4 

try-job: dist-aarch64-linux


Diff:
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index e8c42d16733ec..176fb72dfdc5e 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -1,5 +1,4 @@
 //! Set and unset common attributes on LLVM values.
-
 use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::DefId;
@@ -28,6 +27,22 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
     }
 }
 
+pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool {
+    llvm::HasAttributeAtIndex(llfn, idx, attr)
+}
+
+pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool {
+    llvm::HasStringAttribute(llfn, name)
+}
+
+pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) {
+    llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind);
+}
+
+pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) {
+    llvm::RemoveStringAttrFromFn(llfn, name);
+}
+
 /// Get LLVM attribute for the provided inline heuristic.
 #[inline]
 fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 925898d817371..39b3a23e0b1b0 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -28,8 +28,9 @@ use crate::back::write::{
 use crate::errors::{
     DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
 };
+use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, build_string};
-use crate::{LlvmCodegenBackend, ModuleLlvm};
+use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes};
 
 /// We keep track of the computed LTO cache keys from the previous
 /// session to determine which CGUs we can reuse.
@@ -666,6 +667,31 @@ pub(crate) fn run_pass_manager(
     }
 
     if cfg!(llvm_enzyme) && enable_ad && !thin {
+        let cx =
+            SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size);
+
+        for function in cx.get_functions() {
+            let enzyme_marker = "enzyme_marker";
+            if attributes::has_string_attr(function, enzyme_marker) {
+                // Sanity check: Ensure 'noinline' is present before replacing it.
+                assert!(
+                    !attributes::has_attr(function, Function, llvm::AttributeKind::NoInline),
+                    "Expected __enzyme function to have 'noinline' before adding 'alwaysinline'"
+                );
+
+                attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline);
+                attributes::remove_string_attr_from_llfn(function, enzyme_marker);
+
+                assert!(
+                    !attributes::has_string_attr(function, enzyme_marker),
+                    "Expected function to not have 'enzyme_marker'"
+                );
+
+                let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx);
+                attributes::apply_to_llfn(function, Function, &[always_inline]);
+            }
+        }
+
         let opt_stage = llvm::OptStage::FatLTO;
         let stage = write::AutodiffStage::PostAD;
         if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 0147bd5a66581..c5c13ac097a27 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -361,6 +361,11 @@ fn generate_enzyme_call<'ll>(
         let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
         attributes::apply_to_llfn(ad_fn, Function, &[attr]);
 
+        // We add a made-up attribute just such that we can recognize it after AD to update
+        // (no)-inline attributes. We'll then also remove this attribute.
+        let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker");
+        attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]);
+
         // first, remove all calls from fnc
         let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
         let br = llvm::LLVMRustGetTerminator(entry);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 4ec6999551898..ed50515b70716 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -698,6 +698,16 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
             llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
         })
     }
+
+    pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
+        let mut functions = vec![];
+        let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) };
+        while let Some(f) = func {
+            functions.push(f);
+            func = unsafe { llvm::LLVMGetNextFunction(f) }
+        }
+        functions
+    }
 }
 
 impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index a9b3bdf7344be..2ad39fc853819 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -19,6 +19,19 @@ unsafe extern "C" {
     pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
     pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
     pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
+    pub(crate) fn LLVMRustHasFnAttribute(
+        F: &Value,
+        Name: *const c_char,
+        NameLen: libc::size_t,
+    ) -> bool;
+    pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t);
+    pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
+    pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
+    pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
+        Fn: &Value,
+        index: c_uint,
+        kind: AttributeKind,
+    );
 }
 
 unsafe extern "C" {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 6ca81c651ed42..d14aab060731a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>(
     }
 }
 
+pub(crate) fn HasAttributeAtIndex<'ll>(
+    llfn: &'ll Value,
+    idx: AttributePlace,
+    kind: AttributeKind,
+) -> bool {
+    unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) }
+}
+
+pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool {
+    unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
+}
+
+pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) {
+    unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
+}
+
+pub(crate) fn RemoveRustEnumAttributeAtIndex(
+    llfn: &Value,
+    place: AttributePlace,
+    kind: AttributeKind,
+) {
+    unsafe {
+        LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind);
+    }
+}
+
 pub(crate) fn AddCallSiteAttributes<'ll>(
     callsite: &'ll Value,
     idx: AttributePlace,
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index b89ce90d1a1dc..169036f515298 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -128,6 +128,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
         (**self).borrow().llcx
     }
 
+    pub(crate) fn llmod(&self) -> &'ll llvm::Module {
+        (**self).borrow().llmod
+    }
+
     pub(crate) fn isize_ty(&self) -> &'ll Type {
         (**self).borrow().isize_ty
     }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 5f0e4d745e833..72369ab7b692a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -973,6 +973,27 @@ extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
   return nullptr;
 }
 
+extern "C" void
+LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
+                                   LLVMRustAttributeKind RustAttr) {
+  LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
+}
+
+extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name,
+                                       size_t NameLen) {
+  if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
+    return Fn->hasFnAttribute(StringRef(Name, NameLen));
+  }
+  return false;
+}
+
+extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name,
+                                          size_t NameLen) {
+  if (auto *F = dyn_cast<Function>(unwrap<Value>(Fn))) {
+    F->removeFnAttr(StringRef(Name, NameLen));
+  }
+}
+
 extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
                                           LLVMMetadataRef MD) {
   unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
diff --git a/tests/codegen/autodiff/inline.rs b/tests/codegen/autodiff/inline.rs
new file mode 100644
index 0000000000000..e90faa4aa3802
--- /dev/null
+++ b/tests/codegen/autodiff/inline.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat -Zautodiff=NoPostopt
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff;
+
+#[autodiff(d_square, Reverse, Duplicated, Active)]
+fn square(x: &f64) -> f64 {
+    x * x
+}
+
+// CHECK: ; inline::d_square
+// CHECK-NEXT: ; Function Attrs: alwaysinline
+// CHECK-NOT: noinline
+// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE
+fn main() {
+    let x = std::hint::black_box(3.0);
+    let mut dx1 = std::hint::black_box(1.0);
+    let _ = d_square(&x, &mut dx1, 1.0);
+    assert_eq!(dx1, 6.0);
+}


Reviews:
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-18T23:44:24Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-18T23:45:19Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-19T02:27:48Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-20T02:09:57Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-20T02:14:40Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-20T02:16:37Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-20T06:55:06Z
user: login: ZuseZ4
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T14:22:27Z

Review comments:
diff_hunk: @@ -0,0 +1,20 @@
+//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff;
+
+#[autodiff(d_square, Reverse, Duplicated, Active)]
+fn square(x: &f64) -> f64 {
+    x * x
+}
+// CHECK: ; Function Attrs: alwaysinline noinline
+// CHECK-NEXT: declare double @__enzyme_autodiff_ZN6inline8d_square17h021c74e92c259cdeE(...) local_unnamed_addr #8
path: tests/codegen/autodiff/inline.rs
user: login: ZuseZ4
body: ```suggestion
// CHECK-NOT: noinline
// CHECK-NEXT: declare double @__enzyme_autodiff_ZN6inline8d_square17h021c74e92c259cdeE(...) local_unnamed_addr #8
```
created_at: 2025-04-18T23:44:24Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,20 @@
+//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff;
+
+#[autodiff(d_square, Reverse, Duplicated, Active)]
+fn square(x: &f64) -> f64 {
+    x * x
+}
+// CHECK: ; Function Attrs: alwaysinline noinline
+// CHECK-NEXT: declare double @__enzyme_autodiff_ZN6inline8d_square17h021c74e92c259cdeE(...) local_unnamed_addr #8
path: tests/codegen/autodiff/inline.rs
user: login: ZuseZ4
body: Lit tests don't care about extra text at the end of a test line, so just removing form the CHECK isn't enough, it would still pass.
created_at: 2025-04-18T23:45:18Z
author_association: MEMBER
diff_hunk: @@ -664,6 +665,30 @@ pub(crate) fn run_pass_manager(
             unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) };
         }
 
+        let cx =
+            SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size);
+
+        for function in cx.get_functions() {
+            let name = get_value_name(function);
+            let name = std::str::from_utf8(name).unwrap();
+
+            if name.starts_with("__enzyme") {
+                // Ensure `noinline` is present before replacing it.
+                // This is not strictly necessary for correctness, but serves as a sanity check
+                // in case the autodiff pass stops injecting `noinline` in the future.
+                assert!(
+                    !attributes::has_attr(function, 0, llvm::AttributeKind::NoInline),
path: compiler/rustc_codegen_llvm/src/back/lto.rs
user: login: ZuseZ4
body: If you look at the AttributePlace definition, you'll see that 0 means return attribute, if you want a function it has to be !0. I'd recommend to just use the AttributePlace, like in your other locations. Still investigating why the attribute isn't removed. 
created_at: 2025-04-19T02:27:47Z
author_association: MEMBER
diff_hunk: @@ -334,6 +334,13 @@ fn generate_enzyme_call<'ll>(
         let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
         attributes::apply_to_llfn(ad_fn, Function, &[attr]);
 
+        // We add a made-up attribute just such that we can recognize it after AD to update
+        // (no)-inline attributes. We'll then also remove this attribute.
+        let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker");
+        //Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
path: compiler/rustc_codegen_llvm/src/builder/autodiff.rs
user: login: ZuseZ4
body: commented out code
created_at: 2025-04-20T02:09:57Z
author_association: MEMBER
diff_hunk: @@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>(
     }
 }
 
+pub(crate) fn HasAttributeAtIndex<'ll>(
+    llfn: &'ll Value,
+    idx: AttributePlace,
+    kind: AttributeKind,
+) -> bool {
+    unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) }
+}
+
+pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: *const i8) -> bool {
+    unsafe { LLVMRustHasFnAttribute(llfn, name) }
+}
+
+pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: *const i8) {
+    unsafe { LLVMRustRemoveFnAttribute(llfn, name) }
path: compiler/rustc_codegen_llvm/src/llvm/mod.rs
user: login: ZuseZ4
body: @oli-obk Not for this PR, but shouldn't we at some point add some debug assertion to verify all those functions, instead of just silently ignoring that these wrappers make it trivial to achieve UB from safe code?
E.g. check that name is zero terminated, ~Value is actually a function, etc.~
nvm. I forgot that we usually just return if we give in the wrong type, so it should be safe.
created_at: 2025-04-20T02:14:39Z
author_association: MEMBER
diff_hunk: @@ -1157,6 +1157,15 @@ unsafe extern "C" {
     pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
     pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
     pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
+
+    pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
path: compiler/rustc_codegen_llvm/src/llvm/ffi.rs
user: login: ZuseZ4
body: I made up the convention of only introducing new functions to enzyme_ffi.rs if it's only used by Enzyme.
Only if I find users outside of our own code (or someone else start using it) I put it here in ffi.rs. Not super relevant, but do you mind moving it? That makes it a bit easier to track.
created_at: 2025-04-20T02:16:36Z
author_association: MEMBER
diff_hunk: @@ -973,6 +973,27 @@ extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
   return nullptr;
 }
 
+extern "C" void
+LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
+                                   LLVMRustAttributeKind RustAttr) {
+  LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
+}
+
+extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name) {
+  if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
+    return Fn->hasFnAttribute(Name);
+  }
+  return false;
+}
+
+extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name) {
+  auto *F = dyn_cast<Function>(unwrap<Value>(Fn));
+  assert(F);
path: compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
user: login: ZuseZ4
body: I just wrote these asserts while debugging, can you change it to match the other functions
`if (auto *Fn = ...)` and remove the asserts?
created_at: 2025-04-20T06:55:05Z
author_association: MEMBER
diff_hunk: @@ -666,6 +667,38 @@ pub(crate) fn run_pass_manager(
     }
 
     if cfg!(llvm_enzyme) && enable_ad && !thin {
+        // This is the post-autodiff IR, mainly used for testing and educational purposes.
+        if config.autodiff.contains(&config::AutoDiff::PrintModAfter) {
path: compiler/rustc_codegen_llvm/src/back/lto.rs
user: login: ZuseZ4
body: Did you pick that up from my experimental branch? I think we already handle PrintModAfter elsewhere, so this would print it twice. Can you check and potentially remove this line? Sorry, just noticed it now. Otherwise lgtm
created_at: 2025-04-25T14:22:26Z
author_association: MEMBER

PR comments:
user: login: ZuseZ4
created_at: 2025-04-04T05:50:09Z
body: Thank you for looking into this! 

There are two things to improve here, first we want to write that in safer Rust, and second this currently adds `alwaysinline` everywhere. However, we only want it for the functions we generated. I'd probably start with making it safer, that should be more straightforward, this PR is a good start: https://github.com/rust-lang/rust/pull/135581

As a rule of thumb I often noticed during my autodiff work, that if you want to add something to an LLVM component, then rustc likely already has wrappers for it. If you want to get something out of an LLVM component, chances are you have to write those safe wrappers, since rustc usually just lowers things.

Here is an example I found after using rg (ripgrep) to find inline related matches in rustc_codegen_llvm:
https://github.com/rust-lang/rust/blob/9e14530c7c27123484658c88c2148a552b01e73b/compiler/rustc_codegen_llvm/src/attributes.rs#L33
SimpleCx and CodegenCx are safe wrappers around llvm modules to help you handle things safely. The CodegenCx is more powerful, but also needs more inputs to be constructed. You probably won't be able to generate a full CodegenCx, since you don't have a TypeContext (tcx) available. Instead search for the SimpleCx, you should be able to create one instead. In the next steps we can then use the SimpleCx, to safely replace the 4 LLVM functions which you are currently introducing.

(The way I usually find safe wrappers systematically is by first looking up the llvm function I need, then searching for existing uses (wrappers) in rustc, and then going up the wrapper chain till I find one that I can use.)
author_association: MEMBER
user: login: bors
created_at: 2025-04-05T07:24:12Z
body: :umbrella: The latest upstream changes (presumably #139396) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-12T14:05:38Z
body: @rustbot review
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-12T20:28:34Z
body: Thanks, that looks pretty good now. I'm a bit worried about regressing this, though, since just missing an inline will probably not be noticed immediately. So a `tests/codegen/autodiff/inline.rs` test would be good. Once it landed you should be able to use https://github.com/rust-lang/rust/pull/139700 the `NoPostopt` flag from this PR, and check that the inline attribute is where we expect it to be. https://llvm.org/docs/CommandGuide/lit.html
You can try to copy from the other tests (just add the NoPostopt` flag in the first line), and check for the inline attribute on top of the function. Feel free to push a draft test, and I can help to clean it up.
author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-14T16:58:14Z
body: > Thanks, that looks pretty good now. I'm a bit worried about regressing this, though, since just missing an inline will probably not be noticed immediately. So a `tests/codegen/autodiff/inline.rs` test would be good. Once it landed you should be able to use #139700 the `NoPostopt` flag from this PR, and check that the inline attribute is where we expect it to be. https://llvm.org/docs/CommandGuide/lit.html You can try to copy from the other tests (just add the NoPostopt` flag in the first line), and check for the inline attribute on top of the function. Feel free to push a draft test, and I can help to clean it up.

Hello @ZuseZ4, I’ve locally rebased my PR onto #139700, and in the generated IR, I’m seeing the following:

```llvm
; Function Attrs: alwaysinline noinline
declare double @__enzyme_autodiff_ZN6inline8d_square17h021c74e92c259cdeE(...) local_unnamed_addr #8
```

This looks correct to me. I used `-Z autodiff=NoPostopt` as you suggested.
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-14T17:56:53Z
body: oh, the test is helpful. I'm not sure what LLVM would do, but I think specifying `noinline` `alwaysinline` on the same function will be confusing either for LLVM or developers, probably both. I wouldn't want to rely on whatever behavior it has.

Can you (before adding alwaysinline) go through fn attrs, and assert that there is a noinline attr, with a comment that this check isn't strictly necessary, but just a guard to remind us if this code path ever changes? Then remove the no inline attr before adding always inpine. That should make it more robust.
author_association: MEMBER
user: login: rust-log-analyzer
created_at: 2025-04-15T06:32:16Z
body: 
The job **`x86_64-gnu-tools`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/14462712407/job/40558226289) [(plain)](https://github.com/rust-lang/rust/commit/b149ed415d78de2f0a8090deb95a27b178441249/checks/40558226289/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
   Compiling rustc_borrowck v0.0.0 (/checkout/compiler/rustc_borrowck)
error[E0425]: cannot find value `attrs` in this scope
  --> compiler/rustc_codegen_llvm/src/llvm/mod.rs:49:63
   |
49 |     unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), attrs.as_ptr()) }
   |                                                               ^^^^^ help: a local variable with a similar name exists: `attr`

error[E0308]: arguments to this function are incorrect
   --> compiler/rustc_codegen_llvm/src/back/lto.rs:680:21
    |
680 |                     attributes::has_attr(function, llvm::AttributeKind::NoInline, Function),
    |                     ^^^^^^^^^^^^^^^^^^^^           -----------------------------  -------- argument #3 of type `&llvm::ffi::Attribute` is missing
    |                                                    |
    |                                                    unexpected argument #2 of type `llvm::ffi::AttributeKind`
    |
note: function defined here
   --> compiler/rustc_codegen_llvm/src/attributes.rs:31:15
    |
31  | pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: &Attribute) -> bool {
    |               ^^^^^^^^                                    ----------------
help: did you mean
    |
680 -                     attributes::has_attr(function, llvm::AttributeKind::NoInline, Function),
680 +                     attributes::has_attr(function, Function, /* &llvm::ffi::Attribute */),
    |

Some errors have detailed explanations: E0308, E0425.
For more information about an error, try `rustc --explain E0308`.
[RUSTC-TIMING] rustc_codegen_llvm test:false 3.876
```

</details>

author_association: COLLABORATOR
user: login: rust-log-analyzer
created_at: 2025-04-15T07:09:26Z
body: 
The job **`x86_64-gnu-llvm-19`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/14463282988/job/40559887226) [(plain)](https://github.com/rust-lang/rust/commit/c1063dfb774b6b289ce7e1a194ea8b568a40a5b9/checks/40559887226/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
#19 exporting to docker image format
#19 sending tarball 20.3s done
#19 DONE 26.6s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-19]
[CI_JOB_NAME=x86_64-gnu-llvm-19]
debug: `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` configured.
---
sccache: Listening on address 127.0.0.1:4226
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-19', '--enable-llvm-link-shared', '--set', 'rust.randomize-layout=true', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'build.print-step-timings', '--enable-verbose-tests', '--set', 'build.metrics', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--set', 'rust.lld=false', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: build.build          := x86_64-unknown-linux-gnu
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-19/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.randomize-layout := True
configure: rust.thin-lto-import-instr-limit := 10
---
   Compiling rustc_mir_build v0.0.0 (/checkout/compiler/rustc_mir_build)
[RUSTC-TIMING] rustc_query_impl test:false 38.900
   Compiling rustc_codegen_llvm v0.0.0 (/checkout/compiler/rustc_codegen_llvm)
   Compiling rustc_passes v0.0.0 (/checkout/compiler/rustc_passes)
error[E0425]: cannot find value `llfn` in this scope
   --> compiler/rustc_codegen_llvm/src/back/lto.rs:685:46
    |
685 |                 attributes::remove_from_llfn(llfn, Function, llvm::AttributeKind::NoInline);
    |                                              ^^^^ not found in this scope

error[E0425]: cannot find value `attrs` in this scope
  --> compiler/rustc_codegen_llvm/src/llvm/mod.rs:49:63
   |
49 |     unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), attrs.as_ptr()) }
   |                                                               ^^^^^ help: a local variable with a similar name exists: `attr`

[RUSTC-TIMING] rustc_privacy test:false 6.384
   Compiling rustc_borrowck v0.0.0 (/checkout/compiler/rustc_borrowck)
error[E0308]: mismatched types
   --> compiler/rustc_codegen_llvm/src/back/lto.rs:680:62
    |
680 |                     attributes::has_attr(function, Function, llvm::AttributeKind::NoInline),
    |                     --------------------                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&llvm::ffi::Attribute`, found `AttributeKind`
    |                     |
    |                     arguments to this function are incorrect
    |
   ::: compiler/rustc_codegen_llvm/src/llvm/ffi.rs:749:5
    |
749 |     pub(crate) type Attribute;
    |     ------------------------- the expected foreign type
    |
    = note: expected reference `&llvm::ffi::Attribute`
                    found enum `llvm::ffi::AttributeKind`
note: function defined here
   --> compiler/rustc_codegen_llvm/src/attributes.rs:31:15
    |
31  | pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: &Attribute) -> bool {
    |               ^^^^^^^^                                    ----------------

Some errors have detailed explanations: E0308, E0425.
For more information about an error, try `rustc --explain E0308`.
[RUSTC-TIMING] rustc_codegen_llvm test:false 3.928
```

</details>

author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-15T17:03:37Z
body: Hi @ZuseZ4, I added `LLVMRemoveEnumAttributeAtIndex` to remove the `noinline` attribute from `llfn`, and also implemented a utility method `has_attr` based on `LLVMRustHasAttributeAtIndex`. However, I’m not seeing the `noinline` attribute being removed from the function. Not sure why that’s happening—any suggestions?
author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-18T04:42:23Z
body: @rustbot review
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-19T03:56:12Z
body: Ok, I've experimented a bit. 
First, in one location you use 0, where it should be !0 (or rather use the AttributePlace enum which has a to_cuint() function which lowers correctly and is nicer to use.
I've also realized that you were modifying the `__enzyme` declaration, not the actual function which got generated by enzyme. I'm not sure why the declaration is still around (IMHO enzyme should clean up after itself and remove unused declarations). I've updated the test to test that the actual function which we differentiated lost it's noinline attribute.

In general, your `__enzyme` string matching function was a bit risky, since we should always consider that users give functions arbitrary names. I've instead added some code earlier to the pipeline, which marks source and target function with an `enzyme_marker` attribute. This simplifies the backend, where we now can just iterate through all functions and skip the ones without an enzyme marker. 

As to why your function didn't remove the attribute, I'm not fully sure, but I remember that I ran into the same bug a while ago. I ended up copying me old code here: https://github.com/EnzymeAD/rust/blob/322f2226c1f672c9b5e934b15d255ae0d66bd0e2/compiler/rustc_codegen_llvm/src/back/write.rs#L1195
It indeed ended up working, you can see that the noinline attribute disappears. 

I pushed my code here. Sorry that it's quite messy, I cherry picked both my flags PR and your code (and messed up the cherry picking on top of that). Also, it's not using any pretty wrappers, but it hopefully shows how to remove the attribute.
https://github.com/rust-lang/rust/compare/master...EnzymeAD:rust:noinline-imprv


Either in this or a follow-up PR we should also be a bit more precise, since e.g. the `diffe_` function which got generated by enzyme still has the noinline attribute. It's a newly generated function so there's no way to mark it with `enzyme_marker` before, but we know that our wrapper does nothing but call the `diffe_` function. So whenever we see a function marked with `enzyme_marker`, we could iterate through the instructions in the body to get the diffe function call, and from there the diffe definition. Then we can also strip the noinline from there. But as mentioned, we don't have to do anything in one PR.
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-19T04:12:51Z
body: Ok, I think also remembered again why your approach didn't work. 
If you look at the definition of the AttributeKind, it says that it will match the C++ RustAttributeKind.
It does *not* match the LLVM AttributeKind, for which there is another wrapper there on the C++ side in `compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp` (around line 282).
So if you pass the Rust attribute directly to the LLVM* functions, it will break. If you pass it to the LLVMRust functions and use a `fromRust(attr)`, then it will be matched correctly. You can check it yourself by looking at
`build/x86_64-unknown-linux-gnu/llvm/include/llvm/IR/Attributes.inc`, where we have `NoInline = 32,`.
(So for fun you could try to remove the `StackProtect` attribute, which on the rust side has value 32. Maybe removing StackProtect will remove noinline (but don't do that in the final code). FFI is fun..
Also feel free to add a note to the AttributeKind enum in `compiler/rustc_codegen_llvm/src/llvm/ffi.rs`, making clear that it must *not* be passed to `LLVM*` functions, and only works for `LLVMRust` functions. (And I'd probably let that be verified by another reviewer)
author_association: MEMBER
user: login: rustbot
created_at: 2025-04-19T17:19:51Z
body: Some changes occurred in compiler/rustc_codegen_llvm/src/builder/autodiff.rs

cc @ZuseZ4

Some changes occurred in compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs

cc @ZuseZ4
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-19T17:23:44Z
body: > Ok, I think also remembered again why your approach didn't work. If you look at the definition of the AttributeKind, it says that it will match the C++ RustAttributeKind. It does _not_ match the LLVM AttributeKind, for which there is another wrapper there on the C++ side in `compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp` (around line 282). So if you pass the Rust attribute directly to the LLVM* functions, it will break. If you pass it to the LLVMRust functions and use a `fromRust(attr)`, then it will be matched correctly. You can check it yourself by looking at `build/x86_64-unknown-linux-gnu/llvm/include/llvm/IR/Attributes.inc`, where we have `NoInline = 32,`. (So for fun you could try to remove the `StackProtect` attribute, which on the rust side has value 32. Maybe removing StackProtect will remove noinline (but don't do that in the final code). FFI is fun.. Also feel free to add a note to the AttributeKind enum in `compiler/rustc_codegen_llvm/src/llvm/ffi.rs`, making clear that it must _not_ be passed to `LLVM*` functions, and only works for `LLVMRust` functions. (And I'd probably let that be verified by another reviewer)

That did the trick—`fromRust` was the missing piece. Now `remove_from_llfn` is successfully removing the attributes. Thanks for jogging the memory and pointing out the subtle mismatch—FFI really does keep you humble.
author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-19T17:28:51Z
body: 
> Either in this or a follow-up PR we should also be a bit more precise, since e.g. the `diffe_` function which got generated by enzyme still has the noinline attribute. It's a newly generated function so there's no way to mark it with `enzyme_marker` before, but we know that our wrapper does nothing but call the `diffe_` function. So whenever we see a function marked with `enzyme_marker`, we could iterate through the instructions in the body to get the diffe function call, and from there the diffe definition. Then we can also strip the noinline from there. But as mentioned, we don't have to do anything in one PR.

Thanks a lot for the thorough explanation!. The marker-based approach you added is a big improvement. Totally agree that relying on string matching for `__enzyme` is fragile, especially with user-defined names in play. Using `enzyme_marker` early in the pipeline to annotate both source and target functions makes things much more robust and simplifies things downstream—nice solution!. I'm happy to help clean things up and follow through with refining the approach—especially for that `diffe_` function case you mentioned. That sounds like a good candidate for a follow-up PR where we can safely walk the body and strip `noinline` from any directly-called differentiated functions. Appreciate all the context on this!
author_association: MEMBER
user: login: rust-log-analyzer
created_at: 2025-04-19T17:30:06Z
body: 
The job **`mingw-check-tidy`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/14551288833/job/40822792176) [(plain)](https://github.com/rust-lang/rust/commit/e1266afb61416340aba2b71d171c3bb43afd9104/checks/40822792176/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
info: removing rustup binaries
info: rustup is uninstalled
##[group]Image checksum input
mingw-check-tidy
# We use the ghcr base image because ghcr doesn't have a rate limit
# and the mingw-check-tidy job doesn't cache docker images in CI.
FROM ghcr.io/rust-lang/ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
  g++ \
  make \
---

COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/

# NOTE: intentionally uses python2 for x.py so we can test it still works.
# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test \
           --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
#    pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
---
#12 2.865 Building wheels for collected packages: reuse
#12 2.867   Building wheel for reuse (pyproject.toml): started
#12 3.084   Building wheel for reuse (pyproject.toml): finished with status 'done'
#12 3.085   Created wheel for reuse: filename=reuse-4.0.3-cp310-cp310-manylinux_2_35_x86_64.whl size=132719 sha256=5bb60f62728aaedff7162745ce743c7f2f55069b3e7f82e6a37d70df455797cc
#12 3.085   Stored in directory: /tmp/pip-ephem-wheel-cache-fuodfond/wheels/3d/8d/0a/e0fc6aba4494b28a967ab5eaf951c121d9c677958714e34532
#12 3.087 Successfully built reuse
#12 3.088 Installing collected packages: boolean-py, binaryornot, tomlkit, reuse, python-debian, markupsafe, license-expression, jinja2, chardet, attrs
#12 3.503 Successfully installed attrs-23.2.0 binaryornot-0.4.4 boolean-py-4.0 chardet-5.2.0 jinja2-3.1.4 license-expression-30.3.0 markupsafe-2.1.5 python-debian-0.1.49 reuse-4.0.3 tomlkit-0.13.0
#12 3.504 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
#12 4.054 Collecting virtualenv
#12 4.094   Downloading virtualenv-20.30.0-py3-none-any.whl (4.3 MB)
#12 4.184      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.3/4.3 MB 49.2 MB/s eta 0:00:00
#12 4.240 Collecting platformdirs<5,>=3.9.1
#12 4.245   Downloading platformdirs-4.3.7-py3-none-any.whl (18 kB)
#12 4.282 Collecting filelock<4,>=3.12.2
#12 4.286   Downloading filelock-3.18.0-py3-none-any.whl (16 kB)
#12 4.306 Collecting distlib<1,>=0.3.7
#12 4.310   Downloading distlib-0.3.9-py2.py3-none-any.whl (468 kB)
#12 4.318      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 469.0/469.0 KB 75.2 MB/s eta 0:00:00
#12 4.401 Installing collected packages: distlib, platformdirs, filelock, virtualenv
#12 4.592 Successfully installed distlib-0.3.9 filelock-3.18.0 platformdirs-4.3.7 virtualenv-20.30.0
#12 4.593 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
#12 DONE 4.7s

#13 [7/8] COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
#13 DONE 0.0s
---
DirectMap4k:      137152 kB
DirectMap2M:     6154240 kB
DirectMap1G:    12582912 kB
##[endgroup]
Executing TIDY_PRINT_DIFF=1 python2.7 ../x.py test            --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
+ TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
##[group]Building bootstrap
    Finished `dev` profile [unoptimized] target(s) in 0.05s
##[endgroup]
WARN: currently no CI rustc builds have rustc debug assertions enabled. Please either set `rust.debug-assertions` to `false` if you want to use download CI rustc or set `rust.download-rustc` to `false`.
[TIMING] core::build_steps::tool::LibcxxVersionTool { target: x86_64-unknown-linux-gnu } -- 0.217
---
fmt check
fmt: checked 5984 files
tidy check
tidy: Skipping binary file check, read-only filesystem
removing old virtual environment
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'venv'
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'virtualenv'
Requirement already satisfied: pip in ./build/venv/lib/python3.10/site-packages (25.0.1)
linting python files
All checks passed!
checking python file formatting
26 files already formatted
checking C++ file formatting
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:974:2: error: code should be clang-formatted [-Wclang-format-violations]
}
 ^
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:977:16: error: code should be clang-formatted [-Wclang-format-violations]
extern "C" void LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
               ^
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:977:81: error: code should be clang-formatted [-Wclang-format-violations]
extern "C" void LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
                                                                                ^
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:980:2: error: code should be clang-formatted [-Wclang-format-violations]
}
 ^
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:988:2: error: code should be clang-formatted [-Wclang-format-violations]
}
 ^
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:997:2: error: code should be clang-formatted [-Wclang-format-violations]
}
 ^

clang-format linting failed! Printing diff suggestions:
--- /checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp (actual)
+++ /checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp (formatted)
@@ -972,31 +972,28 @@
   }
   return nullptr;
 }
 
-
-extern "C" void LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
-                                                   LLVMRustAttributeKind RustAttr) {
+extern "C" void
+LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
+                                   LLVMRustAttributeKind RustAttr) {
   LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
 }
-
 
 extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name) {
   if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
     return Fn->hasFnAttribute(Name);
   }
   return false;
 }
 
-
 extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name) {
   auto *F = dyn_cast<Function>(unwrap<Value>(Fn));
   assert(F);
   assert(F->hasFnAttribute(Name) &&
          "Function does not have the attribute to be removed");
   F->removeFnAttr(Name);
 }
-
 
 extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
                                           LLVMMetadataRef MD) {
   unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));

some tidy checks failed
tidy error: checks with external tool 'clang-format' failed
Command has failed. Rerun with -v to see more details.
Build completed unsuccessfully in 0:01:52
  local time: Sat Apr 19 17:29:55 UTC 2025
  network time: Sat, 19 Apr 2025 17:29:56 GMT
##[error]Process completed with exit code 1.
Post job cleanup.
```

</details>

author_association: COLLABORATOR
user: login: ZuseZ4
created_at: 2025-04-20T02:21:19Z
body: Overall looks good, just left some nits. Can you clean up the history now, maybe bring it down to 2-3 commits (or just squash it all if you don't want to deal with it)?


author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-20T11:35:27Z
body: Hey @ZuseZ4,  
I’ve addressed the nits and restructured the commits. This is currently blocked by: https://github.com/rust-lang/rust/pull/139700.  
Everything else is good to go!

author_association: MEMBER
user: login: bors
created_at: 2025-04-24T23:55:09Z
body: :umbrella: The latest upstream changes (presumably #140256) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-25T05:50:33Z
body: Hey @ZuseZ4, this should be good to go now..
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-25T14:24:13Z
body: @bors delegate=@Shoruya742 with print comment adressed
author_association: MEMBER
user: login: bors
created_at: 2025-04-25T14:24:17Z
body: :v: @Shoruya742, you can now approve this pull request!

If @ZuseZ4 told you to "`r=me`" after making some further change, please make that change, then do `@bors r=@ZuseZ4`
<!-- homu: {"type":"Delegated","delegator":"ZuseZ4","delegate":"Shoruya742"} -->
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-26T02:35:31Z
body: @bors r=ZuseZ4
author_association: MEMBER
user: login: bors
created_at: 2025-04-26T02:35:34Z
body: @Shourya742: :key: Insufficient privileges: Not in reviewers
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-26T02:35:50Z
body: @bors r=@ZuseZ4
author_association: MEMBER
user: login: bors
created_at: 2025-04-26T02:35:52Z
body: @Shourya742: :key: Insufficient privileges: Not in reviewers
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-26T02:36:42Z
body: @ZuseZ4 looks like I can't approve.
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-26T13:20:21Z
body: Strange,
@bors r+
author_association: MEMBER
user: login: bors
created_at: 2025-04-26T13:20:23Z
body: :pushpin: Commit 48d05aac9b9aa488702b5519fd16121336468593 has been approved by `ZuseZ4`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust) for this repository.

<!-- @bors r=ZuseZ4 48d05aac9b9aa488702b5519fd16121336468593 -->
<!-- homu: {"type":"Approved","sha":"48d05aac9b9aa488702b5519fd16121336468593","approver":"ZuseZ4","queue":"https://bors.rust-lang.org/homu/queue/rust"} -->
author_association: COLLABORATOR
user: login: jhpratt
created_at: 2025-04-27T01:29:05Z
body: @bors r-

https://github.com/rust-lang/rust/pull/140350#issuecomment-2832670604
author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-27T05:21:08Z
body: Hey @ZuseZ4, it looks like there was a pointer mismatch. I updated all vanilla references to use `*const c_str`. Could we try running the job for `dist-aarch64-linux`?
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-27T05:56:46Z
body: Yes let's try that, but also when comparing it to other code it looks like existing functions (e.g. CreateAttrString) accept &str and use `as_c_char_ptr` from `compiler/rustc_codegen_llvm/src/common.rs`. They then forward both string and len to C++, see e.g. `LLVMRustDIBuilderCreateFile` in RustWrapper.cpp. There they use `StringRef(Filename, FilenameLen)` to be able to use Rust Strings in C++. That would allow you to get rid of the CString. Is there a reason why we can't copy it, or could you update the new wrappers to use it? That should also avoid the pointer type mismatch that we have. 

@bors try
author_association: MEMBER
user: login: bors
created_at: 2025-04-27T05:57:56Z
body: :hourglass: Trying commit bbb9f6cdd3f76b2c8da6d4b956567bfd831d0109 with merge 93ac4be0c9a102e10028aa511237f84031510b8f...
<!-- homu: {"type":"TryBuildStarted","head_sha":"bbb9f6cdd3f76b2c8da6d4b956567bfd831d0109","merge_sha":"93ac4be0c9a102e10028aa511237f84031510b8f"} -->
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-27T06:16:56Z
body: > Yes let's try that, but also when comparing it to other code it looks like existing functions (e.g. CreateAttrString) accept &str and use `as_c_char_ptr` from `compiler/rustc_codegen_llvm/src/common.rs`. They then forward both string and len to C++, see e.g. `LLVMRustDIBuilderCreateFile` in RustWrapper.cpp. There they use `StringRef(Filename, FilenameLen)` to be able to use Rust Strings in C++. That would allow you to get rid of the CString. Is there a reason why we can't copy it, or could you update the new wrappers to use it? That should also avoid the pointer type mismatch that we have.
> 
> @bors try

Let me check this — I was under the impression that with `c_str`, you don't really need to know the length explicitly, since it's terminated by a `\0`.
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-27T06:45:03Z
body: You're right, either solution should work. It's just the question of whether rustc users will need to allocate a CString which is zero terminated, or a Rust String which contains ptr + len. Working with pure Rust types would be nicer, and as I just noticed when checking the build failure, other LLVM wrappers also seem to make use of the ptr+len combination, so I think it would be good if we copy them. In that case you could also remove your CString and replace it with a normal string.

author_association: MEMBER
user: login: bors
created_at: 2025-04-27T08:38:02Z
body: :sunny: Try build successful - [checks-actions](https://github.com/rust-lang-ci/rust/actions/runs/14689004789/job/41224439115)
Build commit: 93ac4be0c9a102e10028aa511237f84031510b8f (`93ac4be0c9a102e10028aa511237f84031510b8f`)
<!-- homu: {"type":"TryBuildCompleted","builders":{"checks-actions":"https://github.com/rust-lang-ci/rust/actions/runs/14689004789/job/41224439115"},"merge_sha":"93ac4be0c9a102e10028aa511237f84031510b8f"} -->
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-27T14:03:08Z
body: @ZuseZ4, should we go ahead and push this in? I can follow up with another PR to replace CString with a Rust String and then use StringRef.
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-28T01:21:01Z
body: Since this isn't about an only partly implemented feature (like improving the inline handling further in the future), but about the code quality of new code, I'd prefer to directly have it nice. Especially, since we already broke rollup CI with this PR due to not using the right types. Sorry for the extra iteration, I also have a checked out version of this branch and can look into the required changes tomorrow, and suggest them in the ui.
author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-28T03:04:22Z
body: > Since this isn't about an only partly implemented feature (like improving the inline handling further in the future), but about the code quality of new code, I'd prefer to directly have it nice. Especially, since we already broke rollup CI with this PR due to not using the right types. Sorry for the extra iteration, I also have a checked out version of this branch and can look into the required changes tomorrow, and suggest them in the ui.

Cool!!! I will get this done..
author_association: MEMBER
user: login: Shourya742
created_at: 2025-04-28T15:14:14Z
body: Hey @ZuseZ4, I’ve added `StringRef` and removed the `CString` dependency here: 30f55e055bcf6480d22259cd5051fac544220fb1. Can we try again and then its good to go.
author_association: MEMBER
user: login: rust-log-analyzer
created_at: 2025-04-28T15:18:30Z
body: 
The job **`mingw-check-tidy`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/14711198917/job/41283851652) [(plain)](https://github.com/rust-lang/rust/commit/30f55e055bcf6480d22259cd5051fac544220fb1/checks/41283851652/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
info: removing rustup binaries
info: rustup is uninstalled
##[group]Image checksum input
mingw-check-tidy
# We use the ghcr base image because ghcr doesn't have a rate limit
# and the mingw-check-tidy job doesn't cache docker images in CI.
FROM ghcr.io/rust-lang/ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
  g++ \
---

COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/

# NOTE: intentionally uses python2 for x.py so we can test it still works.
# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test \
           --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
#    pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
---
#12 2.808 Building wheels for collected packages: reuse
#12 2.809   Building wheel for reuse (pyproject.toml): started
#12 3.020   Building wheel for reuse (pyproject.toml): finished with status 'done'
#12 3.021   Created wheel for reuse: filename=reuse-4.0.3-cp310-cp310-manylinux_2_35_x86_64.whl size=132719 sha256=5bb60f62728aaedff7162745ce743c7f2f55069b3e7f82e6a37d70df455797cc
#12 3.021   Stored in directory: /tmp/pip-ephem-wheel-cache-78z7dmja/wheels/3d/8d/0a/e0fc6aba4494b28a967ab5eaf951c121d9c677958714e34532
#12 3.023 Successfully built reuse
#12 3.024 Installing collected packages: boolean-py, binaryornot, tomlkit, reuse, python-debian, markupsafe, license-expression, jinja2, chardet, attrs
#12 3.430 Successfully installed attrs-23.2.0 binaryornot-0.4.4 boolean-py-4.0 chardet-5.2.0 jinja2-3.1.4 license-expression-30.3.0 markupsafe-2.1.5 python-debian-0.1.49 reuse-4.0.3 tomlkit-0.13.0
#12 3.430 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
#12 3.963 Collecting virtualenv
#12 4.001   Downloading virtualenv-20.30.0-py3-none-any.whl (4.3 MB)
#12 4.062      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.3/4.3 MB 73.7 MB/s eta 0:00:00
#12 4.101 Collecting distlib<1,>=0.3.7
#12 4.104   Downloading distlib-0.3.9-py2.py3-none-any.whl (468 kB)
#12 4.111      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 469.0/469.0 KB 95.1 MB/s eta 0:00:00
#12 4.147 Collecting filelock<4,>=3.12.2
#12 4.150   Downloading filelock-3.18.0-py3-none-any.whl (16 kB)
#12 4.184 Collecting platformdirs<5,>=3.9.1
#12 4.188   Downloading platformdirs-4.3.7-py3-none-any.whl (18 kB)
#12 4.271 Installing collected packages: distlib, platformdirs, filelock, virtualenv
#12 4.455 Successfully installed distlib-0.3.9 filelock-3.18.0 platformdirs-4.3.7 virtualenv-20.30.0
#12 4.455 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
#12 DONE 4.5s

#13 [7/8] COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
#13 DONE 0.0s
---
DirectMap4k:      126912 kB
DirectMap2M:     7213056 kB
DirectMap1G:    11534336 kB
##[endgroup]
Executing TIDY_PRINT_DIFF=1 python2.7 ../x.py test            --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
+ TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
##[group]Building bootstrap
    Finished `dev` profile [unoptimized] target(s) in 0.05s
##[endgroup]
WARN: currently no CI rustc builds have rustc debug assertions enabled. Please either set `rust.debug-assertions` to `false` if you want to use download CI rustc or set `rust.download-rustc` to `false`.
[TIMING] core::build_steps::tool::LibcxxVersionTool { target: x86_64-unknown-linux-gnu } -- 0.214
---
fmt check
fmt: checked 6000 files
tidy check
tidy: Skipping binary file check, read-only filesystem
removing old virtual environment
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'venv'
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'virtualenv'
Requirement already satisfied: pip in ./build/venv/lib/python3.10/site-packages (25.0.1)
Collecting pip
  Downloading pip-25.1-py3-none-any.whl.metadata (3.6 kB)
Downloading pip-25.1-py3-none-any.whl (1.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 99.7 MB/s eta 0:00:00
Installing collected packages: pip
---
All checks passed!
checking python file formatting
26 files already formatted
checking C++ file formatting
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:982:73: error: code should be clang-formatted [-Wclang-format-violations]
extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name, size_t NameLen) {
                                                                        ^
/checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp:989:77: error: code should be clang-formatted [-Wclang-format-violations]
extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name, size_t NameLen) {
                                                                            ^

clang-format linting failed! Printing diff suggestions:
--- /checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp (actual)
+++ /checkout/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp (formatted)
@@ -978,16 +978,18 @@
                                    LLVMRustAttributeKind RustAttr) {
   LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
 }
 
-extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name, size_t NameLen) {
+extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name,
+                                       size_t NameLen) {
   if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
     return Fn->hasFnAttribute(StringRef(Name, NameLen));
   }
   return false;
 }
 
-extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name, size_t NameLen) {
+extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name,
+                                          size_t NameLen) {
   if (auto *F = dyn_cast<Function>(unwrap<Value>(Fn))) {
     F->removeFnAttr(StringRef(Name, NameLen));
   }
 }

tidy error: checks with external tool 'clang-format' failed
some tidy checks failed
Command has failed. Rerun with -v to see more details.
Build completed unsuccessfully in 0:01:46
  local time: Mon Apr 28 15:18:18 UTC 2025
  network time: Mon, 28 Apr 2025 15:18:19 GMT
##[error]Process completed with exit code 1.
Post job cleanup.
```

</details>

author_association: COLLABORATOR
user: login: ZuseZ4
created_at: 2025-04-28T15:21:17Z
body: Looks good, can you merge it into the original commits? Also, you'll need to run `clang-format -i compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp`
author_association: MEMBER
user: login: ZuseZ4
created_at: 2025-04-28T15:44:59Z
body: In the future you should try `git rebase -i` to directly fix the commit introducing the wrong bindings, but for this one we can leave it.
@bors try
author_association: MEMBER
user: login: bors
created_at: 2025-04-28T15:46:10Z
body: :hourglass: Trying commit 7018392337a938e25c9ed9190c4f0966737fffdb with merge f7001f83a1e119aa78162a53900016ef6dc96b28...
<!-- homu: {"type":"TryBuildStarted","head_sha":"7018392337a938e25c9ed9190c4f0966737fffdb","merge_sha":"f7001f83a1e119aa78162a53900016ef6dc96b28"} -->
author_association: COLLABORATOR
user: login: Shourya742
created_at: 2025-04-28T15:55:17Z
body: Done!!!! 
author_association: MEMBER
user: login: bors
created_at: 2025-04-28T17:42:55Z
body: :sunny: Try build successful - [checks-actions](https://github.com/rust-lang-ci/rust/actions/runs/14712004130/job/41293791416)
Build commit: f7001f83a1e119aa78162a53900016ef6dc96b28 (`f7001f83a1e119aa78162a53900016ef6dc96b28`)
<!-- homu: {"type":"TryBuildCompleted","builders":{"checks-actions":"https://github.com/rust-lang-ci/rust/actions/runs/14712004130/job/41293791416"},"merge_sha":"f7001f83a1e119aa78162a53900016ef6dc96b28"} -->
author_association: COLLABORATOR
user: login: ZuseZ4
created_at: 2025-04-28T17:53:21Z
body: @bors r+ rollup
author_association: MEMBER
user: login: bors
created_at: 2025-04-28T17:53:23Z
body: :pushpin: Commit 7018392337a938e25c9ed9190c4f0966737fffdb has been approved by `ZuseZ4`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust) for this repository.

<!-- @bors r=ZuseZ4 7018392337a938e25c9ed9190c4f0966737fffdb -->
<!-- homu: {"type":"Approved","sha":"7018392337a938e25c9ed9190c4f0966737fffdb","approver":"ZuseZ4","queue":"https://bors.rust-lang.org/homu/queue/rust"} -->
author_association: COLLABORATOR
user: login: ZuseZ4
created_at: 2025-04-29T20:24:48Z
body: @jedbrown 

author_association: MEMBER