[llvm] [FunctionAttrs] Handle nofreeobj (PR #218364)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 24 02:57:39 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

<details>
<summary>Changes</summary>

This adds handling for nofreeobj (introduced in https://github.com/llvm/llvm-project/pull/206445) in two places:

 * Don't infer `nofree` if we already have `nofreeobj`. `nofreeobj` is a stronger property, it's pointless to have both.
 * Use `nofreeobj` on call arguments when inferring `nofree`.

---
Full diff: https://github.com/llvm/llvm-project/pull/218364.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/IPO/FunctionAttrs.cpp (+4-2) 
- (modified) llvm/test/Transforms/FunctionAttrs/nofree.ll (+22-3) 


``````````diff
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index d98d3a1c46309..d2f89150ee663 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -952,7 +952,8 @@ determinePointerAccessAttrs(Argument *A,
       if (isModSet(ArgMR) && !CB->onlyReadsMemory(UseIndex)) {
         Props.IsWrite = true;
         if (CB->isArgOperand(U) && !CB->hasFnAttr(Attribute::NoFree) &&
-            !CB->paramHasAttr(UseIndex, Attribute::NoFree))
+            !CB->paramHasAttr(UseIndex, Attribute::NoFree) &&
+            !CB->paramHasAttr(UseIndex, Attribute::NoFreeObj))
           Props.IsFree = true;
       }
     } else {
@@ -1075,7 +1076,8 @@ static bool addAccessAttrs(Argument *A, ArgAccessProperties Props) {
   assert(A && "Argument must not be null.");
 
   bool Changed = false;
-  if (!Props.IsFree && !A->hasAttribute(Attribute::NoFree)) {
+  if (!Props.IsFree && !A->hasAttribute(Attribute::NoFree) &&
+      !A->hasAttribute(Attribute::NoFreeObj)) {
     ++NumNoFreeArg;
     A->addAttr(Attribute::NoFree);
     Changed = true;
diff --git a/llvm/test/Transforms/FunctionAttrs/nofree.ll b/llvm/test/Transforms/FunctionAttrs/nofree.ll
index c477bf8e00aeb..e342ed8f4c198 100644
--- a/llvm/test/Transforms/FunctionAttrs/nofree.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nofree.ll
@@ -103,7 +103,7 @@ define void @_Z4foo7Pi(ptr %a) local_unnamed_addr #1 {
 ; CHECK-NEXT:    [[ISNULL:%.*]] = icmp eq ptr [[A]], null
 ; CHECK-NEXT:    br i1 [[ISNULL]], label %[[DELETE_END:.*]], label %[[DELETE_NOTNULL:.*]]
 ; CHECK:       [[DELETE_NOTNULL]]:
-; CHECK-NEXT:    tail call void @_ZdlPv(ptr [[A]]) #[[ATTR8:[0-9]+]]
+; CHECK-NEXT:    tail call void @_ZdlPv(ptr [[A]]) #[[ATTR9:[0-9]+]]
 ; CHECK-NEXT:    br label %[[DELETE_END]]
 ; CHECK:       [[DELETE_END]]:
 ; CHECK-NEXT:    ret void
@@ -130,7 +130,7 @@ define void @_Z4foo8Pi(ptr %a) local_unnamed_addr #1 {
 ; CHECK-NEXT:    [[ISNULL:%.*]] = icmp eq ptr [[A]], null
 ; CHECK-NEXT:    br i1 [[ISNULL]], label %[[DELETE_END:.*]], label %[[DELETE_NOTNULL:.*]]
 ; CHECK:       [[DELETE_NOTNULL]]:
-; CHECK-NEXT:    tail call void @_ZdaPv(ptr [[A]]) #[[ATTR8]]
+; CHECK-NEXT:    tail call void @_ZdaPv(ptr [[A]]) #[[ATTR9]]
 ; CHECK-NEXT:    br label %[[DELETE_END]]
 ; CHECK:       [[DELETE_END]]:
 ; CHECK-NEXT:    ret void
@@ -252,7 +252,7 @@ define void @passed_to_nofree_fn_maybe_capture_arg(ptr %p) {
 define void @passed_to_readonly_fn_nocapture_arg(ptr %p) {
 ; CHECK-LABEL: define void @passed_to_readonly_fn_nocapture_arg(
 ; CHECK-SAME: ptr nofree readonly captures(address) [[P:%.*]]) {
-; CHECK-NEXT:    call void @takes_ptr(ptr captures(address, read_provenance) [[P]]) #[[ATTR9:[0-9]+]]
+; CHECK-NEXT:    call void @takes_ptr(ptr captures(address, read_provenance) [[P]]) #[[ATTR10:[0-9]+]]
 ; CHECK-NEXT:    call void @may_free()
 ; CHECK-NEXT:    ret void
 ;
@@ -298,6 +298,25 @@ define void @passed_to_unknown_bundle(ptr %p) {
   ret void
 }
 
+define void @already_nofreeobj(ptr nofreeobj %p) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define void @already_nofreeobj(
+; CHECK-SAME: ptr nofreeobj readnone captures(none) [[P:%.*]]) #[[ATTR7:[0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+
+define void @call_with_nofreeobj(ptr %p) {
+; CHECK-LABEL: define void @call_with_nofreeobj(
+; CHECK-SAME: ptr nofree captures(none) [[P:%.*]]) {
+; CHECK-NEXT:    call void @takes_ptr(ptr nofreeobj captures(none) [[P]])
+; CHECK-NEXT:    ret void
+;
+  call void @takes_ptr(ptr nofreeobj captures(none) %p)
+  ret void
+}
+
 declare void @takes_ptr(ptr)
 
 declare void @_ZdaPv(ptr) local_unnamed_addr #4

``````````

</details>


https://github.com/llvm/llvm-project/pull/218364


More information about the llvm-commits mailing list