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

Daniil Fukalov via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 1 13:55:43 PDT 2024


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

>From 3a6f85d45ec1f3f4012a36b3f0942fde46c86a0d Mon Sep 17 00:00:00 2001
From: dfukalov <1671137+dfukalov at users.noreply.github.com>
Date: Thu, 27 Jun 2024 21:46:46 +0200
Subject: [PATCH 1/6] [NFC][AlwaysInliner] Reduce AlwaysInliner memory
 consumption.

Refactored AlwaysInliner to remove some of inlined functions earlier.
Fixes out of memory issue on a huge test case from issue 59126.

Also cleaned up one test.
---
 llvm/lib/Transforms/IPO/AlwaysInliner.cpp     | 105 ++++++++++--------
 .../Inline/always-inline-phase-ordering.ll    |  13 +--
 2 files changed, 63 insertions(+), 55 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index cc375f9badcd4..e97e167412bfe 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -15,12 +15,12 @@
 #include "llvm/ADT/SetVector.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/InlineAdvisor.h"
 #include "llvm/Analysis/InlineCost.h"
 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
 #include "llvm/Analysis/ProfileSummaryInfo.h"
 #include "llvm/IR/Module.h"
 #include "llvm/InitializePasses.h"
-#include "llvm/Transforms/IPO/Inliner.h"
 #include "llvm/Transforms/Utils/Cloning.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 
@@ -38,6 +38,7 @@ bool AlwaysInlineImpl(
   SmallSetVector<CallBase *, 16> Calls;
   bool Changed = false;
   SmallVector<Function *, 16> InlinedFunctions;
+  SmallVector<Function *, 16> WorkList;
   for (Function &F : M) {
     // When callee coroutine function is inlined into caller coroutine function
     // before coro-split pass,
@@ -46,64 +47,74 @@ bool AlwaysInlineImpl(
     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())
+      WorkList.push_back(&F);
+  }
 
-        Changed = true;
+  for (Function *F : WorkList) {
+    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.
-        InlinedFunctions.push_back(&F);
+      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.
+  // Final cleanup stage. Firstly, 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(
+  auto *NonComdatBegin = partition(
       InlinedFunctions, [&](Function *F) { return F->hasComdat(); });
   for (Function *F : make_range(NonComdatBegin, InlinedFunctions.end())) {
     M.getFunctionList().erase(F);
@@ -191,7 +202,7 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M,
   auto &PSI = MAM.getResult<ProfileSummaryAnalysis>(M);
 
   bool Changed = AlwaysInlineImpl(M, InsertLifetime, PSI, GetAssumptionCache,
-                                  GetAAR, GetBFI);
+                                    GetAAR, GetBFI);
 
   return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
 }
diff --git a/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll b/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll
index e69ca48344900..237cf180947bf 100644
--- a/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll
+++ b/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll
@@ -1,12 +1,10 @@
 ; RUN: opt --Os -pass-remarks=inline -S < %s 2>&1 | FileCheck %s
 target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
-target triple = "arm64e-apple-macosx13"
 
 ; CHECK: remark: <unknown>:0:0: 'wibble' inlined into 'bar.8' with (cost=always): always inline attribute
 ; CHECK: remark: <unknown>:0:0: 'wibble' inlined into 'pluto' with (cost=always): always inline attribute
 ; CHECK: remark: <unknown>:0:0: 'snork' inlined into 'blam' with (cost=always): always inline attribute
 ; CHECK: remark: <unknown>:0:0: 'wobble' inlined into 'blam' with (cost=always): always inline attribute
-; CHECK: remark: <unknown>:0:0: 'wobble' inlined into 'snork' with (cost=always): always inline attribute
 ; CHECK: remark: <unknown>:0:0: 'spam' inlined into 'blam' with (cost=65, threshold=75)
 ; CHECK: remark: <unknown>:0:0: 'wibble.1' inlined into 'widget' with (cost=30, threshold=75)
 ; CHECK: remark: <unknown>:0:0: 'widget' inlined into 'bar.8' with (cost=30, threshold=75)
@@ -24,14 +22,14 @@ bb:
   unreachable
 }
 
-define linkonce_odr void @pluto() #1 !prof !38 {
+define linkonce_odr void @pluto() !prof !38 {
 bb:
   call void @wibble()
   ret void
 }
 
 ; Function Attrs: alwaysinline
-define linkonce_odr void @wibble() #2 {
+define linkonce_odr void @wibble() #1 {
 bb:
   call void @widget()
   ret void
@@ -62,7 +60,7 @@ bb:
 }
 
 ; Function Attrs: alwaysinline
-define linkonce_odr i32 @snork() #2 {
+define linkonce_odr i32 @snork() #1 {
 bb:
   %tmpv1 = call i32 @spam()
   %tmpv2 = call i32 @wobble()
@@ -83,7 +81,7 @@ bb:
 }
 
 ; Function Attrs: alwaysinline
-define linkonce_odr i32 @wobble() #2 {
+define linkonce_odr i32 @wobble() #1 {
 bb:
   %tmpv = call i64 @wobble.5(i8 0)
   %tmpv1 = call i64 @eggs.7()
@@ -119,8 +117,7 @@ bb:
 }
 
 attributes #0 = { "frame-pointer"="non-leaf" }
-attributes #1 = { "target-cpu"="apple-m1" }
-attributes #2 = { alwaysinline }
+attributes #1 = { alwaysinline }
 
 !llvm.module.flags = !{!0, !1, !30, !31, !32, !36, !37}
 

>From e3f4142be3abc9f5bc395a1ce54717d7577f4fdd Mon Sep 17 00:00:00 2001
From: dfukalov <1671137+dfukalov at users.noreply.github.com>
Date: Thu, 27 Jun 2024 22:14:39 +0200
Subject: [PATCH 2/6] Addressed comment.

---
 llvm/lib/Transforms/IPO/AlwaysInliner.cpp            |  3 +--
 .../Inline/always-inline-phase-ordering.ll           | 12 +++++++-----
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index e97e167412bfe..02ff549560a30 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -104,7 +104,6 @@ bool AlwaysInlineImpl(
         Changed = true;
       }
     }
-    
   }
 
   // Final cleanup stage. Firstly, remove any live functions.
@@ -202,7 +201,7 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M,
   auto &PSI = MAM.getResult<ProfileSummaryAnalysis>(M);
 
   bool Changed = AlwaysInlineImpl(M, InsertLifetime, PSI, GetAssumptionCache,
-                                    GetAAR, GetBFI);
+                                  GetAAR, GetBFI);
 
   return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
 }
diff --git a/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll b/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll
index 237cf180947bf..defd1f4fd426b 100644
--- a/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll
+++ b/llvm/test/Transforms/Inline/always-inline-phase-ordering.ll
@@ -1,5 +1,6 @@
 ; RUN: opt --Os -pass-remarks=inline -S < %s 2>&1 | FileCheck %s
 target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+target triple = "arm64e-apple-macosx13"
 
 ; CHECK: remark: <unknown>:0:0: 'wibble' inlined into 'bar.8' with (cost=always): always inline attribute
 ; CHECK: remark: <unknown>:0:0: 'wibble' inlined into 'pluto' with (cost=always): always inline attribute
@@ -22,14 +23,14 @@ bb:
   unreachable
 }
 
-define linkonce_odr void @pluto() !prof !38 {
+define linkonce_odr void @pluto() #1 !prof !38 {
 bb:
   call void @wibble()
   ret void
 }
 
 ; Function Attrs: alwaysinline
-define linkonce_odr void @wibble() #1 {
+define linkonce_odr void @wibble() #2 {
 bb:
   call void @widget()
   ret void
@@ -60,7 +61,7 @@ bb:
 }
 
 ; Function Attrs: alwaysinline
-define linkonce_odr i32 @snork() #1 {
+define linkonce_odr i32 @snork() #2 {
 bb:
   %tmpv1 = call i32 @spam()
   %tmpv2 = call i32 @wobble()
@@ -81,7 +82,7 @@ bb:
 }
 
 ; Function Attrs: alwaysinline
-define linkonce_odr i32 @wobble() #1 {
+define linkonce_odr i32 @wobble() #2 {
 bb:
   %tmpv = call i64 @wobble.5(i8 0)
   %tmpv1 = call i64 @eggs.7()
@@ -117,7 +118,8 @@ bb:
 }
 
 attributes #0 = { "frame-pointer"="non-leaf" }
-attributes #1 = { alwaysinline }
+attributes #1 = { "target-cpu"="apple-m1" }
+attributes #2 = { alwaysinline }
 
 !llvm.module.flags = !{!0, !1, !30, !31, !32, !36, !37}
 

>From 3a2078ea7a8cdf9ede7fcbeabb0219ff1b038143 Mon Sep 17 00:00:00 2001
From: dfukalov <1671137+dfukalov at users.noreply.github.com>
Date: Mon, 1 Jul 2024 16:04:29 +0200
Subject: [PATCH 3/6] Addressed comments.

---
 llvm/lib/Transforms/IPO/AlwaysInliner.cpp | 40 ++++++++---------------
 1 file changed, 14 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index 02ff549560a30..9290435bab640 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -38,25 +38,19 @@ bool AlwaysInlineImpl(
   SmallSetVector<CallBase *, 16> Calls;
   bool Changed = false;
   SmallVector<Function *, 16> InlinedFunctions;
-  SmallVector<Function *, 16> WorkList;
-  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())
-      WorkList.push_back(&F);
-  }
+    if (F.isDeclaration() || !isInlineViable(F).isSuccess())
+      continue;
 
-  for (Function *F : WorkList) {
     Calls.clear();
 
-    for (User *U : F->users())
+    for (User *U : F.users())
       if (auto *CB = dyn_cast<CallBase>(U))
-        if (CB->getCalledFunction() == F &&
+        if (CB->getCalledFunction() == &F &&
               CB->hasFnAttr(Attribute::AlwaysInline) &&
               !CB->getAttributes().hasFnAttr(Attribute::NoInline))
             Calls.insert(CB);
@@ -69,15 +63,15 @@ bool AlwaysInlineImpl(
 
       InlineFunctionInfo IFI(GetAssumptionCache, &PSI,
                               GetBFI ? &GetBFI(*Caller) : nullptr,
-                              GetBFI ? &GetBFI(*F) : nullptr);
+                              GetBFI ? &GetBFI(F) : nullptr);
 
       InlineResult Res = InlineFunction(*CB, IFI, /*MergeAttributes=*/true,
-                                        &GetAAR(*F), InsertLifetime);
+                                        &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("Callee", &F) << "' is not inlined into '"
                   << ore::NV("Caller", Caller)
                   << "': " << ore::NV("Reason", Res.getFailureReason());
         });
@@ -85,20 +79,20 @@ bool AlwaysInlineImpl(
       }
 
       emitInlinedIntoBasedOnCost(
-          ORE, DLoc, Block, *F, *Caller,
+          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()) {
+    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);
+      if (F.hasComdat()) {
+        InlinedFunctions.push_back(&F);
       } else {
         M.getFunctionList().erase(F);
         Changed = true;
@@ -106,12 +100,6 @@ bool AlwaysInlineImpl(
     }
   }
 
-  // Final cleanup stage. Firstly, 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(); });

>From f51d5417975068d09f6594cb1cde46d8f313c8cc Mon Sep 17 00:00:00 2001
From: dfukalov <1671137+dfukalov at users.noreply.github.com>
Date: Mon, 1 Jul 2024 16:59:12 +0200
Subject: [PATCH 4/6] clang-format

---
 llvm/lib/Transforms/IPO/AlwaysInliner.cpp | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index 9290435bab640..d73518c627bd7 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -51,9 +51,9 @@ bool AlwaysInlineImpl(
     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);
+            CB->hasFnAttr(Attribute::AlwaysInline) &&
+            !CB->getAttributes().hasFnAttr(Attribute::NoInline))
+          Calls.insert(CB);
 
     for (CallBase *CB : Calls) {
       Function *Caller = CB->getCaller();
@@ -62,18 +62,17 @@ bool AlwaysInlineImpl(
       BasicBlock *Block = CB->getParent();
 
       InlineFunctionInfo IFI(GetAssumptionCache, &PSI,
-                              GetBFI ? &GetBFI(*Caller) : nullptr,
-                              GetBFI ? &GetBFI(F) : nullptr);
+                             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());
+          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;
       }
@@ -101,8 +100,8 @@ bool AlwaysInlineImpl(
   }
 
   // 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())) {
     M.getFunctionList().erase(F);
     Changed = true;

>From f29f1d2aaa3b843cf750f8f220c6e74013891ded Mon Sep 17 00:00:00 2001
From: dfukalov <1671137+dfukalov at users.noreply.github.com>
Date: Mon, 1 Jul 2024 22:36:59 +0200
Subject: [PATCH 5/6] removed obsolete part of InlinedFunctions.

---
 llvm/lib/Transforms/IPO/AlwaysInliner.cpp | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index d73518c627bd7..517d3c3f81155 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -37,7 +37,7 @@ bool AlwaysInlineImpl(
     function_ref<BlockFrequencyInfo &(Function &)> GetBFI) {
   SmallSetVector<CallBase *, 16> Calls;
   bool Changed = false;
-  SmallVector<Function *, 16> InlinedFunctions;
+  SmallVector<Function *, 16> InlinedComdatFunctions;
 
   for (Function &F : make_early_inc_range(M)) {
     if (F.isPresplitCoroutine())
@@ -91,7 +91,7 @@ bool AlwaysInlineImpl(
       // 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);
+        InlinedComdatFunctions.push_back(&F);
       } else {
         M.getFunctionList().erase(F);
         Changed = true;
@@ -99,21 +99,12 @@ bool AlwaysInlineImpl(
     }
   }
 
-  // Delete the non-comdat ones from the module and also from our vector.
-  auto *NonComdatBegin =
-      partition(InlinedFunctions, [&](Function *F) { return F->hasComdat(); });
-  for (Function *F : make_range(NonComdatBegin, InlinedFunctions.end())) {
-    M.getFunctionList().erase(F);
-    Changed = true;
-  }
-  InlinedFunctions.erase(NonComdatBegin, InlinedFunctions.end());
-
-  if (!InlinedFunctions.empty()) {
+  if (!InlinedComdatFunctions.empty()) {
     // Now we just have the comdat functions. Filter out the ones whose comdats
     // are not actually dead.
-    filterDeadComdatFunctions(InlinedFunctions);
+    filterDeadComdatFunctions(InlinedComdatFunctions);
     // The remaining functions are actually dead.
-    for (Function *F : InlinedFunctions) {
+    for (Function *F : InlinedComdatFunctions) {
       M.getFunctionList().erase(F);
       Changed = true;
     }

>From c0aa14d134b70273fe10fb1bbea2c8de519ba755 Mon Sep 17 00:00:00 2001
From: dfukalov <1671137+dfukalov at users.noreply.github.com>
Date: Mon, 1 Jul 2024 22:55:10 +0200
Subject: [PATCH 6/6] Comment updated.

---
 llvm/lib/Transforms/IPO/AlwaysInliner.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index 517d3c3f81155..1f787c733079e 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -87,9 +87,8 @@ bool AlwaysInlineImpl(
 
     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.
+      // Remember to try and delete this function afterward. This allows to call
+      // filterDeadComdatFunctions() only once.
       if (F.hasComdat()) {
         InlinedComdatFunctions.push_back(&F);
       } else {



More information about the llvm-commits mailing list