[llvm] [ObjCARC] Allow removal of autoreleasepools (PR #85493)

John McCall via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 18 09:51:13 PDT 2024


================
@@ -756,6 +756,76 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F,
   LLVM_DEBUG(dbgs() << "New: " << *AutoreleaseRV << "\n");
 }
 
+/// Interprocedurally determine if calls made by the given call site can
+/// possibly produce autoreleases.
+bool MayAutorelease(const CallBase &CB, unsigned Depth = 0) {
+  if (const Function *Callee = CB.getCalledFunction()) {
+    if (!Callee->hasExactDefinition())
+      return true;
+    // This recursion depth limit is big enough to cover the vast majority
+    // of cases this will ever require.
+    if (Depth > 64)
+      return true;
+    for (const BasicBlock &BB : *Callee) {
+      for (const Instruction &I : BB)
+        if (const CallBase *JCB = dyn_cast<CallBase>(&I))
+          if (!JCB->onlyReadsMemory() && MayAutorelease(*JCB, Depth + 1))
+            return true;
+    }
+    return false;
+  }
+
+  return true;
+}
+
+// Remove autorelease pools if nothing is in between then
+bool ObjCARCOpt::OptimizeAutoreleasePools(Function &F) {
+  bool didChange = false;
+  Instruction *Push = nullptr;
+  for (BasicBlock &BB : F) {
+    bool foundAnyInBlock = false;
+    for (Instruction &Inst : BB) {
+      // FIXME: For now, only support pairs that are in the same block.
+      // It is possible to do this across other blocks, but only if you can
+      // prove every single pop call site corresponds to the push via going
+      // through each successor and checking every single one, and I don't even
+      // know if the push call could be split across call sites.
+      switch (GetBasicARCInstKind(&Inst)) {
+      case ARCInstKind::AutoreleasepoolPush:
+        Push = &Inst;
+        foundAnyInBlock = true;
+        break;
+      case ARCInstKind::AutoreleasepoolPop:
+        // If this pop matches a push and nothing in between can autorelease,
+        // zap the pair.
+        if (cast<CallInst>(&Inst)->getArgOperand(0) == Push &&
+            foundAnyInBlock) {
+          Changed = true;
+          didChange = true;
+          LLVM_DEBUG(dbgs()
+                     << "ObjCARCAPElim::OptimizeBB: Zapping push pop "
+                        "autorelease pair:\n"
+                        "                           Pop: "
+                     << Inst << "\n"
+                     << "                           Push: " << *Push << "\n");
+
+          Inst.eraseFromParent();
+          Push->eraseFromParent();
+        }
+        Push = nullptr;
+        break;
+      case ARCInstKind::CallOrUser:
+        if (MayAutorelease(cast<CallBase>(Inst)))
+          Push = nullptr;
----------------
rjmccall wrote:

Please only do this analysis if there's actually a `push` we're considering optimizing.

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


More information about the llvm-commits mailing list