[llvm] [NFC][AlwaysInliner] Reduce AlwaysInliner memory consumption. (PR #96958)

Arthur Eubanks via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 1 11:29:37 PDT 2024


================
@@ -38,73 +38,70 @@ bool AlwaysInlineImpl(
   SmallSetVector<CallBase *, 16> Calls;
   bool Changed = false;
   SmallVector<Function *, 16> InlinedFunctions;
-  for (Function &F : M) {
-    // When callee coroutine function is inlined into caller coroutine function
-    // before coro-split pass,
-    // coro-early pass can not handle this quiet well.
-    // So we won't inline the coroutine function if it have not been unsplited
+
+  for (Function &F : make_early_inc_range(M)) {
     if (F.isPresplitCoroutine())
       continue;
 
-    if (!F.isDeclaration() && isInlineViable(F).isSuccess()) {
-      Calls.clear();
-
-      for (User *U : F.users())
-        if (auto *CB = dyn_cast<CallBase>(U))
-          if (CB->getCalledFunction() == &F &&
-                CB->hasFnAttr(Attribute::AlwaysInline) &&
-                !CB->getAttributes().hasFnAttr(Attribute::NoInline))
-              Calls.insert(CB);
-
-      for (CallBase *CB : Calls) {
-        Function *Caller = CB->getCaller();
-        OptimizationRemarkEmitter ORE(Caller);
-        DebugLoc DLoc = CB->getDebugLoc();
-        BasicBlock *Block = CB->getParent();
-
-        InlineFunctionInfo IFI(GetAssumptionCache, &PSI,
-                               GetBFI ? &GetBFI(*Caller) : nullptr,
-                               GetBFI ? &GetBFI(F) : nullptr);
-
-        InlineResult Res = InlineFunction(*CB, IFI, /*MergeAttributes=*/true,
-                                          &GetAAR(F), InsertLifetime);
-        if (!Res.isSuccess()) {
-          ORE.emit([&]() {
-            return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc,
-                                            Block)
-                   << "'" << ore::NV("Callee", &F) << "' is not inlined into '"
-                   << ore::NV("Caller", Caller)
-                   << "': " << ore::NV("Reason", Res.getFailureReason());
-          });
-          continue;
-        }
-
-        emitInlinedIntoBasedOnCost(
-            ORE, DLoc, Block, F, *Caller,
-            InlineCost::getAlways("always inline attribute"),
-            /*ForProfileContext=*/false, DEBUG_TYPE);
+    if (F.isDeclaration() || !isInlineViable(F).isSuccess())
+      continue;
 
-        Changed = true;
+    Calls.clear();
+
+    for (User *U : F.users())
+      if (auto *CB = dyn_cast<CallBase>(U))
+        if (CB->getCalledFunction() == &F &&
+            CB->hasFnAttr(Attribute::AlwaysInline) &&
+            !CB->getAttributes().hasFnAttr(Attribute::NoInline))
+          Calls.insert(CB);
+
+    for (CallBase *CB : Calls) {
+      Function *Caller = CB->getCaller();
+      OptimizationRemarkEmitter ORE(Caller);
+      DebugLoc DLoc = CB->getDebugLoc();
+      BasicBlock *Block = CB->getParent();
+
+      InlineFunctionInfo IFI(GetAssumptionCache, &PSI,
+                             GetBFI ? &GetBFI(*Caller) : nullptr,
+                             GetBFI ? &GetBFI(F) : nullptr);
+
+      InlineResult Res = InlineFunction(*CB, IFI, /*MergeAttributes=*/true,
+                                        &GetAAR(F), InsertLifetime);
+      if (!Res.isSuccess()) {
+        ORE.emit([&]() {
+          return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
+                 << "'" << ore::NV("Callee", &F) << "' is not inlined into '"
+                 << ore::NV("Caller", Caller)
+                 << "': " << ore::NV("Reason", Res.getFailureReason());
+        });
+        continue;
       }
 
-      if (F.hasFnAttribute(Attribute::AlwaysInline)) {
-        // Remember to try and delete this function afterward. This both avoids
-        // re-walking the rest of the module and avoids dealing with any
-        // iterator invalidation issues while deleting functions.
+      emitInlinedIntoBasedOnCost(
+          ORE, DLoc, Block, F, *Caller,
+          InlineCost::getAlways("always inline attribute"),
+          /*ForProfileContext=*/false, DEBUG_TYPE);
+
+      Changed = true;
+    }
+
+    F.removeDeadConstantUsers();
+    if (F.hasFnAttribute(Attribute::AlwaysInline) && F.isDefTriviallyDead()) {
+      // Remember to try and delete this function afterward. This both avoids
+      // re-walking the rest of the module and avoids dealing with any
+      // iterator invalidation issues while deleting functions.
+      if (F.hasComdat()) {
         InlinedFunctions.push_back(&F);
+      } else {
+        M.getFunctionList().erase(F);
+        Changed = true;
       }
     }
   }
 
-  // Remove any live functions.
-  erase_if(InlinedFunctions, [&](Function *F) {
-    F->removeDeadConstantUsers();
-    return !F->isDefTriviallyDead();
-  });
-
   // Delete the non-comdat ones from the module and also from our vector.
-  auto NonComdatBegin = partition(
-      InlinedFunctions, [&](Function *F) { return F->hasComdat(); });
+  auto *NonComdatBegin =
+      partition(InlinedFunctions, [&](Function *F) { return F->hasComdat(); });
   for (Function *F : make_range(NonComdatBegin, InlinedFunctions.end())) {
----------------
aeubanks wrote:

this part is obsolete now right? we don't have any non-comdat functions in `InlinedFunctions` (should also change the variable name to `InlinedComdatFunctions`

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


More information about the llvm-commits mailing list