[llvm] [ValueLattice][SCCP] Consider provenance for predicate-derived pointer constants (PR #160083)
Antonio Frighetto via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 7 01:02:52 PDT 2026
https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/160083
>From 0fc66d28749bd807a786d8a46ec5d11ac7ff255c Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Mon, 22 Sep 2025 12:02:41 +0200
Subject: [PATCH 1/4] [ValueLattice][SCCP] Consider provenance for
predicate-derived pointer constants
Similarly to what it is being already done in GVN (fb632ed2377d280b581b8d4653b855e60d611f77),
make sure pointers equalities derived via PredicatedInfo may be
propagated so long as pointer constants' provenance is taken
into account, which may be non-existent. This is achieved by
tracking this in ValueLatticeElement and restrain replacement
to uses allowed by `canReplacePointersInUseIfEqual`.
Fixes: https://github.com/llvm/llvm-project/issues/159565.
---
llvm/include/llvm/Analysis/ValueLattice.h | 14 ++-
.../llvm/Transforms/Utils/SCCPSolver.h | 5 +
llvm/lib/Analysis/Loads.cpp | 4 +-
llvm/lib/Transforms/IPO/SCCP.cpp | 3 +-
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 45 +++++++-
.../SCCP/assume-equality-pointers.ll | 100 ++++++++++++++++++
...eferenceable-ptr-with-undereferenceable.ll | 4 +-
7 files changed, 164 insertions(+), 11 deletions(-)
create mode 100644 llvm/test/Transforms/SCCP/assume-equality-pointers.ll
diff --git a/llvm/include/llvm/Analysis/ValueLattice.h b/llvm/include/llvm/Analysis/ValueLattice.h
index 262ff58f07dfd..560bcbabe09cf 100644
--- a/llvm/include/llvm/Analysis/ValueLattice.h
+++ b/llvm/include/llvm/Analysis/ValueLattice.h
@@ -80,6 +80,11 @@ class ValueLatticeElement {
/// Number of times a constant range has been extended with widening enabled.
unsigned NumRangeExtensions : 8;
+ // Pointer constants derived from equality predicates may have different
+ // provenance than the original value. Limit constant propagation if this
+ // happens to be the case.
+ bool MayHaveDifferentProvenance = false;
+
/// The union either stores a pointer to a constant or a constant range,
/// associated to the lattice element. We have to ensure that Range is
/// initialized or destroyed when changing state to or from constantrange.
@@ -148,7 +153,8 @@ class ValueLatticeElement {
~ValueLatticeElement() { destroy(); }
ValueLatticeElement(const ValueLatticeElement &Other)
- : Tag(Other.Tag), NumRangeExtensions(0) {
+ : Tag(Other.Tag), NumRangeExtensions(0),
+ MayHaveDifferentProvenance(Other.MayHaveDifferentProvenance) {
switch (Other.Tag) {
case constantrange:
case constantrange_including_undef:
@@ -167,7 +173,8 @@ class ValueLatticeElement {
}
ValueLatticeElement(ValueLatticeElement &&Other)
- : Tag(Other.Tag), NumRangeExtensions(0) {
+ : Tag(Other.Tag), NumRangeExtensions(0),
+ MayHaveDifferentProvenance(Other.MayHaveDifferentProvenance) {
switch (Other.Tag) {
case constantrange:
case constantrange_including_undef:
@@ -492,6 +499,9 @@ class ValueLatticeElement {
unsigned getNumRangeExtensions() const { return NumRangeExtensions; }
void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; }
+
+ bool mayHaveDifferentProvenance() const { return MayHaveDifferentProvenance; }
+ void setMayHaveDifferentProvenance(bool V) { MayHaveDifferentProvenance = V; }
};
static_assert(sizeof(ValueLatticeElement) <= 40,
diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
index 5aac7c2ac5d3e..f20e36454c6c1 100644
--- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
+++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
@@ -218,6 +218,11 @@ class SCCPSolver {
// old ValueLatticeElement::isOverdefined() and is intended to be used in the
// transition to ValueLatticeElement.
LLVM_ABI static bool isOverdefined(const ValueLatticeElement &LV);
+
+ // Helper to check if \p LV is a replaceable constant. A pointer constant with
+ // potentially different provenance may not be unconditionally propagated to
+ // all uses.
+ LLVM_ABI static bool isReplaceableConstant(const ValueLatticeElement &LV);
};
} // namespace llvm
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 2e855f918c913..108ba23b1794c 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -803,7 +803,7 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BatchAAResults &AA,
// Returns true if a use is either in an ICmp/PtrToInt or a Phi/Select that only
// feeds into them.
-static bool isPointerUseReplacable(const Use &U, bool HasNonAddressBits) {
+static bool isPointerUseReplaceable(const Use &U, bool HasNonAddressBits) {
unsigned Limit = 40;
SmallVector<const User *> Worklist({U.getUser()});
SmallPtrSet<const User *, 8> Visited;
@@ -859,7 +859,7 @@ bool llvm::canReplacePointersInUseIfEqual(const Use &U, const Value *To,
bool HasNonAddressBits =
DL.getAddressSizeInBits(Ty) != DL.getPointerTypeSizeInBits(Ty);
- return isPointerUseReplacable(U, HasNonAddressBits);
+ return isPointerUseReplaceable(U, HasNonAddressBits);
}
bool llvm::canReplacePointersIfEqual(const Value *From, const Value *To,
diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp
index 2ecadd529170f..7994c73e17302 100644
--- a/llvm/lib/Transforms/IPO/SCCP.cpp
+++ b/llvm/lib/Transforms/IPO/SCCP.cpp
@@ -277,7 +277,8 @@ static bool runIPSCCP(
for (const auto &[F, ReturnValue] : Solver.getTrackedRetVals()) {
assert(!F->getReturnType()->isVoidTy() &&
"should not track void functions");
- if (SCCPSolver::isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef())
+ if (SCCPSolver::isReplaceableConstant(ReturnValue) ||
+ ReturnValue.isUnknownOrUndef())
findReturnsToZap(*F, ReturnsToZap, Solver);
}
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 0ac99413a2cf8..6993ce7fd552f 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/ValueLattice.h"
#include "llvm/Analysis/ValueLatticeUtils.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -57,6 +58,14 @@ bool SCCPSolver::isConstant(const ValueLatticeElement &LV) {
(LV.isConstantRange() && LV.getConstantRange().isSingleElement());
}
+bool SCCPSolver::isReplaceableConstant(const ValueLatticeElement &LV) {
+ if (!isConstant(LV))
+ return false;
+ if (LV.mayHaveDifferentProvenance())
+ return false;
+ return true;
+}
+
bool SCCPSolver::isOverdefined(const ValueLatticeElement &LV) {
return !LV.isUnknownOrUndef() && !SCCPSolver::isConstant(LV);
}
@@ -83,6 +92,32 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) {
return false;
}
+ // For pointer constants derived from PredicateInfo, the constant may have
+ // different provenance. Take this into account during constant pointer
+ // propagation.
+ if (V->getType()->isPointerTy()) {
+ const auto &LV = getLatticeValueFor(V);
+ if (LV.mayHaveDifferentProvenance()) {
+ const DataLayout *DL = nullptr;
+ if (auto *I = dyn_cast<Instruction>(V))
+ DL = &I->getDataLayout();
+ else if (auto *A = dyn_cast<Argument>(V))
+ DL = &A->getParent()->getDataLayout();
+
+ if (!DL)
+ return false;
+
+ bool Changed = V->replaceUsesWithIf(Const, [&](Use &U) {
+ bool CanReplace = canReplacePointersInUseIfEqual(U, Const, *DL);
+ if (CanReplace)
+ LLVM_DEBUG(dbgs() << " Constant pointer: " << *Const << " = " << *V
+ << '\n');
+ return CanReplace;
+ });
+ return Changed;
+ }
+ }
+
LLVM_DEBUG(dbgs() << " Constant: " << *Const << " = " << *V << '\n');
// Replaces all of the uses of a variable with uses of the constant.
@@ -356,11 +391,11 @@ bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB,
if (Inst.getType()->isVoidTy())
continue;
if (tryToReplaceWithConstant(&Inst)) {
- if (wouldInstructionBeTriviallyDead(&Inst))
+ if (isInstructionTriviallyDead(&Inst)) {
Inst.eraseFromParent();
-
+ ++InstRemovedStat;
+ }
MadeChanges = true;
- ++InstRemovedStat;
} else if (replaceSignedInst(*this, InsertedValues, Inst)) {
MadeChanges = true;
++InstReplacedStat;
@@ -1122,7 +1157,7 @@ bool SCCPInstVisitor::isStructLatticeConstant(Function *F, StructType *STy) {
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
const auto &It = TrackedMultipleRetVals.find(std::make_pair(F, i));
assert(It != TrackedMultipleRetVals.end());
- if (!SCCPSolver::isConstant(It->second))
+ if (!SCCPSolver::isReplaceableConstant(It->second))
return false;
}
return true;
@@ -2079,6 +2114,8 @@ void SCCPInstVisitor::handlePredicate(Instruction *I, Value *CopyOf,
// For non-integer values or integer constant expressions, only
// propagate equal constants or not-constants.
addAdditionalUser(OtherOp, I);
+ if (CopyOf->getType()->isPointerTy())
+ CondVal.setMayHaveDifferentProvenance(true);
mergeInValue(IV, I, CondVal);
return;
} else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant()) {
diff --git a/llvm/test/Transforms/SCCP/assume-equality-pointers.ll b/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
new file mode 100644
index 0000000000000..8c01e29f2d074
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
@@ -0,0 +1,100 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=ipsccp -S | FileCheck %s
+
+define ptr @assume_pointers_equality_maybe_different_provenance_1(ptr %x) {
+; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_1(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: ret ptr [[X]]
+;
+entry:
+ %cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
+ call void @llvm.assume(i1 %cmp)
+ ret ptr %x
+}
+
+define ptr @assume_pointers_equality_maybe_different_provenance_2(ptr %x, i1 %cond) {
+; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_2(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: br i1 [[COND]], label %[[NEXT:.*]], label %[[EXIT:.*]]
+; CHECK: [[NEXT]]:
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[X]], %[[ENTRY]] ], [ inttoptr (i64 12345678 to ptr), %[[NEXT]] ]
+; CHECK-NEXT: ret ptr [[PHI]]
+;
+entry:
+ %cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
+ call void @llvm.assume(i1 %cmp)
+ br i1 %cond, label %next, label %exit
+
+next:
+ br label %exit
+
+exit:
+ %phi = phi ptr [ %x, %entry ], [ inttoptr (i64 12345678 to ptr), %next ]
+ ret ptr %phi
+}
+
+define internal ptr @callee(ptr returned %p) memory(none) {
+; CHECK-LABEL: define internal ptr @callee(
+; CHECK-SAME: ptr returned [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret ptr [[P]]
+;
+entry:
+ ret ptr %p
+}
+
+define ptr @assume_pointers_equality_maybe_different_provenance_3(ptr %x, i1 %cond) {
+; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_3(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: br i1 [[COND]], label %[[NEXT:.*]], label %[[EXIT:.*]]
+; CHECK: [[NEXT]]:
+; CHECK-NEXT: [[SEL:%.*]] = select i1 true, ptr [[X]], ptr inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[X]], %[[ENTRY]] ], [ [[SEL]], %[[NEXT]] ]
+; CHECK-NEXT: [[Q:%.*]] = call ptr @callee(ptr [[PHI]])
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND]], ptr [[Q]], ptr [[X]]
+; CHECK-NEXT: ret ptr [[SEL2]]
+;
+entry:
+ %cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
+ call void @llvm.assume(i1 %cmp)
+ br i1 %cond, label %next, label %exit
+
+next:
+ %sel = select i1 %cond, ptr %x, ptr inttoptr (i64 12345678 to ptr)
+ br label %exit
+
+exit:
+ %phi = phi ptr [ %x, %entry ], [ %sel, %next ]
+ %q = call ptr @callee(ptr %phi)
+ %sel2 = select i1 %cond, ptr %q, ptr %x
+ ret ptr %sel2
+}
+
+define i1 @assume_pointers_equality_can_replace_valid(ptr %x, ptr %y) {
+; CHECK-LABEL: define i1 @assume_pointers_equality_can_replace_valid(
+; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr inttoptr (i64 12345678 to ptr), [[Y]]
+; CHECK-NEXT: ret i1 [[CMP2]]
+;
+ %cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
+ call void @llvm.assume(i1 %cmp)
+ %cmp2 = icmp eq ptr %x, %y
+ ret i1 %cmp2
+}
+
+declare void @llvm.assume(i1)
diff --git a/llvm/test/Transforms/SCCP/replace-dereferenceable-ptr-with-undereferenceable.ll b/llvm/test/Transforms/SCCP/replace-dereferenceable-ptr-with-undereferenceable.ll
index 39af513a4506c..f336fcbe70c77 100644
--- a/llvm/test/Transforms/SCCP/replace-dereferenceable-ptr-with-undereferenceable.ll
+++ b/llvm/test/Transforms/SCCP/replace-dereferenceable-ptr-with-undereferenceable.ll
@@ -11,7 +11,7 @@ define i32 @eq_undereferenceable(ptr %p) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P:%.*]], getelementptr inbounds (i32, ptr @x, i64 1)
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: store i32 2, ptr getelementptr inbounds (i32, ptr @x, i64 1), align 4
+; CHECK-NEXT: store i32 2, ptr [[P]], align 4
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @y, align 4
@@ -65,7 +65,7 @@ define i1 @eq_undereferenceable_cmp_simp(ptr %p) {
; CHECK-NEXT: [[CMP_0:%.*]] = icmp eq ptr [[P:%.*]], getelementptr inbounds (i32, ptr @x, i64 1)
; CHECK-NEXT: br i1 [[CMP_0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: store i32 2, ptr getelementptr inbounds (i32, ptr @x, i64 1), align 4
+; CHECK-NEXT: store i32 2, ptr [[P]], align 4
; CHECK-NEXT: ret i1 true
; CHECK: if.end:
; CHECK-NEXT: ret i1 false
>From 2d170054a5c62d09bd26fdf641124f3cb601137e Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Wed, 17 Jun 2026 10:50:50 +0200
Subject: [PATCH 2/4] !fixup update state when merging two lattice values, add
test
---
llvm/include/llvm/Analysis/ValueLattice.h | 9 +++--
.../SCCP/assume-equality-pointers.ll | 35 +++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ValueLattice.h b/llvm/include/llvm/Analysis/ValueLattice.h
index 560bcbabe09cf..705ad9a05be0f 100644
--- a/llvm/include/llvm/Analysis/ValueLattice.h
+++ b/llvm/include/llvm/Analysis/ValueLattice.h
@@ -432,8 +432,13 @@ class ValueLatticeElement {
}
if (isConstant()) {
- if (RHS.isConstant() && getConstant() == RHS.getConstant())
- return false;
+ if (RHS.isConstant() && getConstant() == RHS.getConstant()) {
+ // Equal constants may still differ in provenance, propagate it when
+ // merging values.
+ bool Current = MayHaveDifferentProvenance;
+ MayHaveDifferentProvenance |= RHS.mayHaveDifferentProvenance();
+ return MayHaveDifferentProvenance != Current;
+ }
if (RHS.isUndef())
return false;
// If the constant is a vector of integers, try to treat it as a range.
diff --git a/llvm/test/Transforms/SCCP/assume-equality-pointers.ll b/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
index 8c01e29f2d074..d6232f79962f1 100644
--- a/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
+++ b/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
@@ -83,6 +83,41 @@ exit:
ret ptr %sel2
}
+define i32 @assume_pointers_equality_maybe_different_provenance_4(ptr %x, i1 %cond) {
+; CHECK-LABEL: define i32 @assume_pointers_equality_maybe_different_provenance_4(
+; CHECK-SAME: ptr [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: br i1 [[COND]], label %[[BB_FIRST:.*]], label %[[BB_SECOND:.*]]
+; CHECK: [[BB_FIRST]]:
+; CHECK-NEXT: br label %[[MERGE:.*]]
+; CHECK: [[BB_SECOND]]:
+; CHECK-NEXT: br label %[[MERGE]]
+; CHECK: [[MERGE]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ inttoptr (i64 12345678 to ptr), %[[BB_SECOND]] ], [ [[X]], %[[BB_FIRST]] ]
+; CHECK-NEXT: store i32 0, ptr [[PHI]], align 4
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[PHI]], align 4
+; CHECK-NEXT: ret i32 [[V]]
+;
+entry:
+ %cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
+ call void @llvm.assume(i1 %cmp)
+ br i1 %cond, label %bb.first, label %bb.second
+
+bb.first:
+ br label %merge
+
+bb.second:
+ br label %merge
+
+merge:
+ %phi = phi ptr [ inttoptr (i64 12345678 to ptr), %bb.second ], [ %x, %bb.first ]
+ store i32 0, ptr %phi
+ %v = load i32, ptr %phi
+ ret i32 %v
+}
+
define i1 @assume_pointers_equality_can_replace_valid(ptr %x, ptr %y) {
; CHECK-LABEL: define i1 @assume_pointers_equality_can_replace_valid(
; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
>From 0b8f8aaccdc4edd9cca8ee9e2a9665d7f3aa96a7 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Mon, 29 Jun 2026 09:18:28 +0200
Subject: [PATCH 3/4] !fixup store dl, visitgep handling
---
.../llvm/Transforms/Utils/SCCPSolver.h | 2 ++
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 27 ++++++++++---------
.../SCCP/assume-equality-pointers.ll | 14 ++++++++++
3 files changed, 31 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
index f20e36454c6c1..88a4df83304f1 100644
--- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
+++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
@@ -74,6 +74,8 @@ class SCCPSolver {
LLVM_ABI ~SCCPSolver();
+ LLVM_ABI const DataLayout &getDataLayout() const;
+
LLVM_ABI void addPredicateInfo(Function &F, DominatorTree &DT,
AssumptionCache &AC);
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 6993ce7fd552f..96dc9e1063ade 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -98,17 +98,9 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) {
if (V->getType()->isPointerTy()) {
const auto &LV = getLatticeValueFor(V);
if (LV.mayHaveDifferentProvenance()) {
- const DataLayout *DL = nullptr;
- if (auto *I = dyn_cast<Instruction>(V))
- DL = &I->getDataLayout();
- else if (auto *A = dyn_cast<Argument>(V))
- DL = &A->getParent()->getDataLayout();
-
- if (!DL)
- return false;
-
+ const DataLayout &DL = getDataLayout();
bool Changed = V->replaceUsesWithIf(Const, [&](Use &U) {
- bool CanReplace = canReplacePointersInUseIfEqual(U, Const, *DL);
+ bool CanReplace = canReplacePointersInUseIfEqual(U, Const, DL);
if (CanReplace)
LLVM_DEBUG(dbgs() << " Constant pointer: " << *Const << " = " << *V
<< '\n');
@@ -853,6 +845,8 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
void visitInstruction(Instruction &I);
public:
+ const DataLayout &getDataLayout() const { return DL; }
+
void addPredicateInfo(Function &F, DominatorTree &DT, AssumptionCache &AC) {
FnPredicateInfo.insert({&F, std::make_unique<PredicateInfo>(
F, DT, AC, PredicateInfoAllocator)});
@@ -1871,9 +1865,14 @@ void SCCPInstVisitor::visitGetElementPtrInst(GetElementPtrInst &I) {
return (void)markOverdefined(&I);
}
- if (Constant *C = ConstantFoldInstOperands(&I, Operands, DL))
+ if (Constant *C = ConstantFoldInstOperands(&I, Operands, DL)) {
markConstant(&I, C);
- else
+ // The pointer operand's lattice has found to be a constant, however, the
+ // returned pointer of the GEP may not be freely substituted, as it may have
+ // been derived from a pointer with potentially different provenance.
+ if (PtrState.mayHaveDifferentProvenance())
+ ValueState[&I].setMayHaveDifferentProvenance(true);
+ } else
markOverdefined(&I);
}
@@ -2358,6 +2357,10 @@ SCCPSolver::SCCPSolver(
SCCPSolver::~SCCPSolver() = default;
+const DataLayout &SCCPSolver::getDataLayout() const {
+ return Visitor->getDataLayout();
+}
+
void SCCPSolver::addPredicateInfo(Function &F, DominatorTree &DT,
AssumptionCache &AC) {
Visitor->addPredicateInfo(F, DT, AC);
diff --git a/llvm/test/Transforms/SCCP/assume-equality-pointers.ll b/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
index d6232f79962f1..487c22bc83a7c 100644
--- a/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
+++ b/llvm/test/Transforms/SCCP/assume-equality-pointers.ll
@@ -118,6 +118,20 @@ merge:
ret i32 %v
}
+define ptr @assume_pointers_equality_maybe_different_provenance_5(ptr %x) {
+; CHECK-LABEL: define ptr @assume_pointers_equality_maybe_different_provenance_5(
+; CHECK-SAME: ptr [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], inttoptr (i64 12345678 to ptr)
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[X]], i64 8
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+ %cmp = icmp eq ptr %x, inttoptr (i64 12345678 to ptr)
+ call void @llvm.assume(i1 %cmp)
+ %gep = getelementptr i8, ptr %x, i64 8
+ ret ptr %gep
+}
+
define i1 @assume_pointers_equality_can_replace_valid(ptr %x, ptr %y) {
; CHECK-LABEL: define i1 @assume_pointers_equality_can_replace_valid(
; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
>From 9c563e9f708fa4011d943e96cf97011ee292be34 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 7 Aug 2026 10:02:05 +0200
Subject: [PATCH 4/4] !fixup improve code
---
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 7efc843be9401..cc7fb66e7e0b7 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -59,11 +59,7 @@ bool SCCPSolver::isConstant(const ValueLatticeElement &LV) {
}
bool SCCPSolver::isReplaceableConstant(const ValueLatticeElement &LV) {
- if (!isConstant(LV))
- return false;
- if (LV.mayHaveDifferentProvenance())
- return false;
- return true;
+ return isConstant(LV) && !LV.mayHaveDifferentProvenance();
}
bool SCCPSolver::isOverdefined(const ValueLatticeElement &LV) {
More information about the llvm-commits
mailing list