[llvm] [BasicAA] Check common underlying objects before complex PHI bailouts (PR #228779)

Dávid Bolvanský via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 3 14:57:53 PDT 2026


https://github.com/davidbolvansky created https://github.com/llvm/llvm-project/pull/228779

BasicAA currently bails out on complex PHIs even when all incoming values share an identified underlying object. Before returning `MayAlias`, use the existing bounded, provenance-preserving object lookup to prove disjointness from another identified object.

This changes three comparisons in the existing `loop_phi_chain` test to `NoAlias`. [Compile-time tracker](https://llvm-compile-time-tracker.com/compare.php?from=88dd82f800f46c3ec4c16932a705091434e17ae0&to=d0b6c4116c8dc5a620060442bc34835633445390&stat=instructions:u) instruction-count geomean changes range from -0.01% to +0.03%.

This change was developed with assistance from OpenAI Codex.


>From 6cd098bed7347d98a7820b2f67a8a2e322d77ef3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1vid=20Bolvansk=C3=BD?= <david.bolvansky at gmail.com>
Date: Sat, 3 Oct 2026 23:01:55 +0200
Subject: [PATCH 1/2] [BasicAA] Resolve common objects at complex PHI bailouts

---
 llvm/lib/Analysis/BasicAliasAnalysis.cpp | 17 +++++++++++++++--
 llvm/test/Analysis/BasicAA/phi-aa.ll     |  8 ++++----
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 3aece3ca7d769..aaca6a5161a33 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1459,6 +1459,19 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize,
     return false;
   };
 
+  // Before giving up on a complex PHI, try to resolve a single underlying
+  // object. Keep this off the normal path and only compare identified objects.
+  auto AliasComplexPHI = [&]() {
+    const Value *OtherObject = getUnderlyingObject(V2);
+    if (!EnableRecPhiAnalysis || !isIdentifiedObject(OtherObject))
+      return AliasResult::MayAlias;
+    const Value *Object =
+        getUnderlyingObjectAggressive(PN, /*MustPreserveProvenance=*/true);
+    return Object != OtherObject && isIdentifiedObject(Object)
+               ? AliasResult::NoAlias
+               : AliasResult::MayAlias;
+  };
+
   SmallPtrSet<Value *, 4> UniqueSrc;
   Value *OnePhi = nullptr;
   for (Value *PV1 : PN->incoming_values()) {
@@ -1473,7 +1486,7 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize,
         // that we handle the single phi case as that lets us handle LCSSA
         // phi nodes and (combined with the recursive phi handling) simple
         // pointer induction variable patterns.
-        return AliasResult::MayAlias;
+        return AliasComplexPHI();
       }
       OnePhi = PV1;
     }
@@ -1488,7 +1501,7 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize,
   if (OnePhi && UniqueSrc.size() > 1)
     // Out of an abundance of caution, allow only the trivial lcssa and
     // recursive phi cases.
-    return AliasResult::MayAlias;
+    return AliasComplexPHI();
 
   // If V1Srcs is empty then that means that the phi has no underlying non-phi
   // value. This should only be possible in blocks unreachable from the entry
diff --git a/llvm/test/Analysis/BasicAA/phi-aa.ll b/llvm/test/Analysis/BasicAA/phi-aa.ll
index d5d2142b2093d..d19a3d79922a4 100644
--- a/llvm/test/Analysis/BasicAA/phi-aa.ll
+++ b/llvm/test/Analysis/BasicAA/phi-aa.ll
@@ -80,11 +80,11 @@ declare void @inc(ptr)
 
 ; When we have a chain of phis in nested loops we should recognise if there's
 ; actually only one underlying value.
-; FIXME: All of these could be NoAlias.
+; All three PHIs have @X as their only underlying object.
 ; CHECK-LABEL: loop_phi_chain
-; CHECK: MayAlias: i32* %val1, i32* @Y
-; CHECK: MayAlias: i32* %val2, i32* @Y
-; CHECK: MayAlias: i32* %val3, i32* @Y
+; CHECK: NoAlias: i32* %val1, i32* @Y
+; CHECK: NoAlias: i32* %val2, i32* @Y
+; CHECK: NoAlias: i32* %val3, i32* @Y
 define void @loop_phi_chain(i32 %a, i32 %b, i32 %c) {
 entry:
   br label %loop1

>From d0b6c4116c8dc5a620060442bc34835633445390 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1vid=20Bolvansk=C3=BD?= <david.bolvansky at gmail.com>
Date: Sat, 3 Oct 2026 23:07:49 +0200
Subject: [PATCH 2/2] [BasicAA] Use a shared complex PHI bailout block

---
 llvm/lib/Analysis/BasicAliasAnalysis.cpp | 33 +++++++++++-------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index aaca6a5161a33..267ea6e89ac5c 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1459,21 +1459,9 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize,
     return false;
   };
 
-  // Before giving up on a complex PHI, try to resolve a single underlying
-  // object. Keep this off the normal path and only compare identified objects.
-  auto AliasComplexPHI = [&]() {
-    const Value *OtherObject = getUnderlyingObject(V2);
-    if (!EnableRecPhiAnalysis || !isIdentifiedObject(OtherObject))
-      return AliasResult::MayAlias;
-    const Value *Object =
-        getUnderlyingObjectAggressive(PN, /*MustPreserveProvenance=*/true);
-    return Object != OtherObject && isIdentifiedObject(Object)
-               ? AliasResult::NoAlias
-               : AliasResult::MayAlias;
-  };
-
   SmallPtrSet<Value *, 4> UniqueSrc;
   Value *OnePhi = nullptr;
+  bool HasMultiplePHIs = false;
   for (Value *PV1 : PN->incoming_values()) {
     // Skip the phi itself being the incoming value.
     if (PV1 == PN)
@@ -1486,7 +1474,8 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize,
         // that we handle the single phi case as that lets us handle LCSSA
         // phi nodes and (combined with the recursive phi handling) simple
         // pointer induction variable patterns.
-        return AliasComplexPHI();
+        HasMultiplePHIs = true;
+        break;
       }
       OnePhi = PV1;
     }
@@ -1498,10 +1487,18 @@ AliasResult BasicAAResult::aliasPHI(const PHINode *PN, LocationSize PNSize,
       V1Srcs.push_back(PV1);
   }
 
-  if (OnePhi && UniqueSrc.size() > 1)
-    // Out of an abundance of caution, allow only the trivial lcssa and
-    // recursive phi cases.
-    return AliasComplexPHI();
+  if (HasMultiplePHIs || (OnePhi && UniqueSrc.size() > 1)) {
+    // Avoid recursively comparing complex PHIs. A bounded object lookup may
+    // still prove NoAlias if all incoming values share an identified object.
+    const Value *OtherObject = getUnderlyingObject(V2);
+    if (!EnableRecPhiAnalysis || !isIdentifiedObject(OtherObject))
+      return AliasResult::MayAlias;
+    const Value *Object =
+        getUnderlyingObjectAggressive(PN, /*MustPreserveProvenance=*/true);
+    if (Object != OtherObject && isIdentifiedObject(Object))
+      return AliasResult::NoAlias;
+    return AliasResult::MayAlias;
+  }
 
   // If V1Srcs is empty then that means that the phi has no underlying non-phi
   // value. This should only be possible in blocks unreachable from the entry



More information about the llvm-commits mailing list