[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