[llvm] [ObjCARC] Change autorelease to release when the pool state is not changed between the autorelease and the pool pop (PR #152353)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 18 11:53:06 PDT 2025


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/152353

>From e2faed63bdfee685b65d7e54825953c3197192e3 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Wed, 6 Aug 2025 14:07:16 -0400
Subject: [PATCH 1/4] [ObjCARC] Change autorelease to release when the pool
 state is not changed between the autorelease and the pool pop

---
 llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp   | 56 +++++++++++++++++--
 .../ObjCARC/test_autorelease_pool.ll          |  2 +-
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index 66a2c7632aadc..5598d5f221024 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -121,6 +121,44 @@ static const Value *FindSingleUseIdentifiedObject(const Value *Arg) {
 /// \defgroup ARCOpt ARC Optimization.
 /// @{
 
+/// Check if there is an autoreleasePoolPop after the given autorelease
+/// instruction in the same basic block with no intervening calls that
+/// could affect the autorelease pool.
+static bool HasFollowingAutoreleasePoolPop(Instruction *AutoreleaseInst) {
+  BasicBlock *BB = AutoreleaseInst->getParent();
+
+  // Look forward from the autorelease instruction
+  for (BasicBlock::iterator I = std::next(AutoreleaseInst->getIterator()),
+                            E = BB->end();
+       I != E; ++I) {
+    ARCInstKind Class = GetBasicARCInstKind(&*I);
+
+    switch (Class) {
+    case ARCInstKind::AutoreleasepoolPop:
+      // Found a pool pop - the autorelease will be drained
+      return true;
+
+    case ARCInstKind::AutoreleasepoolPush:
+      // A new pool started - this autorelease won't be drained by a later pop
+      return false;
+
+    case ARCInstKind::CallOrUser:
+    case ARCInstKind::Call:
+      // Unknown call could affect autorelease pool state or return autoreleased
+      // objects
+      return false;
+
+    default:
+      // Known ObjC runtime calls and other instructions are safe to continue
+      // through
+      break;
+    }
+  }
+
+  // Reached end of basic block without finding a pool pop
+  return false;
+}
+
 // TODO: On code like this:
 //
 // objc_retain(%x)
@@ -978,12 +1016,22 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(Function &F, Instruction *Inst,
     break;
   }
 
-  // objc_autorelease(x) -> objc_release(x) if x is otherwise unused.
+  // objc_autorelease(x) -> objc_release(x) if x is otherwise unused
+  // OR if this autorelease is followed by an autoreleasePoolPop.
   if (IsAutorelease(Class) && Inst->use_empty()) {
     CallInst *Call = cast<CallInst>(Inst);
     const Value *Arg = Call->getArgOperand(0);
     Arg = FindSingleUseIdentifiedObject(Arg);
-    if (Arg) {
+    bool ShouldConvert = (Arg != nullptr);
+    const char *Reason = "since x is otherwise unused";
+
+    // Also convert if this autorelease is followed by a pool pop
+    if (!ShouldConvert && HasFollowingAutoreleasePoolPop(Inst)) {
+      ShouldConvert = true;
+      Reason = "since it's followed by autoreleasePoolPop";
+    }
+
+    if (ShouldConvert) {
       Changed = true;
       ++NumAutoreleases;
 
@@ -997,8 +1045,8 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(Function &F, Instruction *Inst,
                            MDNode::get(C, {}));
 
       LLVM_DEBUG(dbgs() << "Replacing autorelease{,RV}(x) with objc_release(x) "
-                           "since x is otherwise unused.\nOld: "
-                        << *Call << "\nNew: " << *NewCall << "\n");
+                        << Reason << ".\nOld: " << *Call
+                        << "\nNew: " << *NewCall << "\n");
 
       EraseInstruction(Call);
       Inst = NewCall;
diff --git a/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll b/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
index 896717f92146f..6c7cfeb78dd3a 100644
--- a/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
+++ b/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
@@ -44,7 +44,7 @@ define void @test_multiple_autoreleases() {
 ; CHECK-NEXT:    call void @use_object(ptr [[OBJ1]])
 ; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ1]]) #[[ATTR0]]
 ; CHECK-NEXT:    call void @use_object(ptr [[OBJ2]])
-; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ2]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
 ; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[POOL]]) #[[ATTR0]]
 ; CHECK-NEXT:    ret void
 ;

>From b5cd34c42d7dc787fecbbce7a80a11f60df79e86 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Wed, 6 Aug 2025 15:29:41 -0400
Subject: [PATCH 2/4] Update test_autorelease_pool.ll

---
 llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll b/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
index 6c7cfeb78dd3a..150837f922c39 100644
--- a/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
+++ b/llvm/test/Transforms/ObjCARC/test_autorelease_pool.ll
@@ -211,9 +211,7 @@ define void @test_complex_shadowing() {
 ; CHECK-NEXT:    [[OBJ3:%.*]] = call ptr @create_object()
 ; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ1]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
 ; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ2]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
-; CHECK-NEXT:    [[INNER2_POOL:%.*]] = call ptr @llvm.objc.autoreleasePoolPush() #[[ATTR0]]
-; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @llvm.objc.autorelease(ptr [[OBJ3]]) #[[ATTR0]]
-; CHECK-NEXT:    call void @llvm.objc.autoreleasePoolPop(ptr [[INNER2_POOL]]) #[[ATTR0]]
+; CHECK-NEXT:    call void @llvm.objc.release(ptr [[OBJ3]]) #[[ATTR0]], !clang.imprecise_release [[META0]]
 ; CHECK-NEXT:    ret void
 ;
   %obj1 = call ptr @create_object()

>From 81550546ec2b49f344ea0982c314abbe22ab0c85 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 19 Aug 2025 13:19:06 -0400
Subject: [PATCH 3/4] Update llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp

Co-authored-by: Jon Roelofs <jroelofs at gmail.com>
---
 llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index 5598d5f221024..27e96b15761d8 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -125,6 +125,7 @@ static const Value *FindSingleUseIdentifiedObject(const Value *Arg) {
 /// instruction in the same basic block with no intervening calls that
 /// could affect the autorelease pool.
 static bool HasFollowingAutoreleasePoolPop(Instruction *AutoreleaseInst) {
+  assert(IsAutorelease(GetBasicARCInstKind(AutoreleaseInst));
   BasicBlock *BB = AutoreleaseInst->getParent();
 
   // Look forward from the autorelease instruction

>From d287ebd5f3d2b3c6803e37b2bffe0c925fa8a076 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Thu, 18 Sep 2025 14:52:46 -0400
Subject: [PATCH 4/4] Update ObjCARCOpts.cpp

---
 llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index 27e96b15761d8..0fbc4997e1d79 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -148,12 +148,6 @@ static bool HasFollowingAutoreleasePoolPop(Instruction *AutoreleaseInst) {
       // Unknown call could affect autorelease pool state or return autoreleased
       // objects
       return false;
-
-    default:
-      // Known ObjC runtime calls and other instructions are safe to continue
-      // through
-      break;
-    }
   }
 
   // Reached end of basic block without finding a pool pop



More information about the llvm-commits mailing list