[llvm] [Attributor] Only seed live internal callees during deduction (PR #222226)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 23:21:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: int-zjt

<details>
<summary>Changes</summary>

When a basic block becomes live, assumeLive marks its internal callees
live to seed attributes for deduction. Currently, this also happens when
a liveness AA is initialized during MANIFEST or CLEANUP, after the
fixed-point iteration has finished.

In CGSCC runs, cleanup can query the liveness of a shared caller for each
callee SCC. Seeding all internal callees in that caller's live blocks
can then cause quadratic initialization work.

Restrict this bulk seeding to SEEDING and UPDATE. Continue recording live
blocks and allow on-demand attribute queries in the later stages.

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


3 Files Affected:

- (modified) llvm/include/llvm/Transforms/IPO/Attributor.h (+8-2) 
- (modified) llvm/lib/Transforms/IPO/AttributorAttributes.cpp (+3) 
- (modified) llvm/unittests/Transforms/IPO/AttributorTest.cpp (+48) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 00b20eee4d5df..066883afafb95 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -1705,7 +1705,7 @@ struct Attributor {
     AAPtr = &AA;
 
     // Register AA with the synthetic root only before the manifest stage.
-    if (Phase == AttributorPhase::SEEDING || Phase == AttributorPhase::UPDATE)
+    if (isDuringDeduction())
       DG.SyntheticRoot.Deps.insert(
           AADepGraphNode::DepTy(&AA, unsigned(DepClassTy::REQUIRED)));
 
@@ -1745,7 +1745,7 @@ struct Attributor {
   template <typename AAType> bool shouldUpdateAA(const IRPosition &IRP) {
     // If this is queried in the manifest stage, we force the AA to indicate
     // pessimistic fixpoint immediately.
-    if (Phase == AttributorPhase::MANIFEST || Phase == AttributorPhase::CLEANUP)
+    if (!isDuringDeduction())
       return false;
 
     Function *AssociatedFn = IRP.getAssociatedFunction();
@@ -1821,6 +1821,12 @@ struct Attributor {
            (Configuration.IPOAmendableCB && Configuration.IPOAmendableCB(F));
   }
 
+  /// Return whether attributes can participate in fixed-point deduction.
+  bool isDuringDeduction() const {
+    return Phase == AttributorPhase::SEEDING ||
+           Phase == AttributorPhase::UPDATE;
+  }
+
   /// Mark the internal function \p F as live.
   ///
   /// This will trigger the identification and initialization of attributes for
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 22af6f7741544..ac4268f78143d 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -4673,6 +4673,9 @@ struct AAIsDeadFunction : public AAIsDead {
     if (!AssumedLiveBlocks.insert(&BB).second)
       return false;
 
+    if (!A.isDuringDeduction())
+      return true;
+
     // We assume that all of BB is (probably) live now and if there are calls to
     // internal functions we will assume that those are now live as well. This
     // is a performance optimization for blocks with calls to a lot of internal
diff --git a/llvm/unittests/Transforms/IPO/AttributorTest.cpp b/llvm/unittests/Transforms/IPO/AttributorTest.cpp
index 8d90b308f840c..9d3d64f75a458 100644
--- a/llvm/unittests/Transforms/IPO/AttributorTest.cpp
+++ b/llvm/unittests/Transforms/IPO/AttributorTest.cpp
@@ -212,4 +212,52 @@ TEST_F(AttributorTestBase, AAReachabilityTest) {
   ASSERT_FALSE(F9AA.instructionCanReach(A, F9FirstInst, F4));
 }
 
+TEST_F(AttributorTestBase, CleanupDoesNotSeedLiveCallees) {
+  for (bool SeedCaller : {false, true}) {
+    SCOPED_TRACE(SeedCaller);
+    Module &M = parseModule(R"(
+      define internal void @leaf() { ret void }
+      define internal void @sibling() { ret void }
+      define void @caller() {
+        call void @leaf()
+        call void @sibling()
+        ret void
+      }
+    )");
+    SetVector<Function *> Functions;
+    for (Function &F : M)
+      Functions.insert(&F);
+    AnalysisGetter AG;
+    CallGraphUpdater CGUpdater;
+    BumpPtrAllocator Allocator;
+    InformationCache InfoCache(M, AG, Allocator, nullptr);
+    AttributorConfig AC(CGUpdater);
+    AC.DefaultInitializeLiveInternals = false;
+    unsigned NumInitializations = 0;
+    // This callback observes markLiveInternalFunction without seeding other
+    // AAs.
+    AC.InitializationCallback = [&](Attributor &, const Function &) {
+      ++NumInitializations;
+    };
+    Attributor A(Functions, InfoCache, AC);
+    auto CallerPos = IRPosition::function(*M.getFunction("caller"));
+    EXPECT_EQ(A.lookupAAFor<AAIsDead>(CallerPos, nullptr, DepClassTy::NONE,
+                                      /*AllowInvalidState=*/true),
+              nullptr);
+    if (SeedCaller) {
+      // Control: discovering a live block during seeding still seeds callees.
+      A.getOrCreateAAFor<AAIsDead>(CallerPos);
+      EXPECT_EQ(NumInitializations, 2u);
+    }
+
+    // Without an initial AA, cleanup's dead-function check creates caller's
+    // liveness AA. Its initializer must not seed leaf or sibling.
+    EXPECT_EQ(A.run(), ChangeStatus::UNCHANGED);
+    EXPECT_NE(A.lookupAAFor<AAIsDead>(CallerPos, nullptr, DepClassTy::NONE,
+                                      /*AllowInvalidState=*/true),
+              nullptr);
+    EXPECT_EQ(NumInitializations, SeedCaller ? 2u : 0u);
+  }
+}
+
 } // namespace llvm

``````````

</details>


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


More information about the llvm-commits mailing list