[llvm] [GVN] Reuse dominating PtrToInt for PtrToAddr. (PR #209164)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 13 06:40:08 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/209164
>From 7e4ad10ea4803b1f34b7ceecc421b0504202eb80 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 13 Jul 2026 13:23:10 +0100
Subject: [PATCH 1/3] [GVN] Add more ptrtoaddr/ptrtoint tests: PRE and CFG
merging.
---
llvm/test/Transforms/GVN/ptrtoaddr.ll | 45 +++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/llvm/test/Transforms/GVN/ptrtoaddr.ll b/llvm/test/Transforms/GVN/ptrtoaddr.ll
index a731ef433741a..359e16d0c39df 100644
--- a/llvm/test/Transforms/GVN/ptrtoaddr.ll
+++ b/llvm/test/Transforms/GVN/ptrtoaddr.ll
@@ -74,3 +74,48 @@ define i64 @ptrtoaddr_wrong_type(ptr %p) {
%r = add i64 %z, %a
ret i64 %r
}
+
+define i64 @ptrtoint_not_pred_from_ptrtoaddr(ptr %p, i1 %c) {
+; CHECK-LABEL: define i64 @ptrtoint_not_pred_from_ptrtoaddr(
+; CHECK-SAME: ptr [[P:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = ptrtoaddr ptr [[P]] to i64
+; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK: [[THEN]]:
+; CHECK-NEXT: br label %[[MERGE:.*]]
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: br label %[[MERGE]]
+; CHECK: [[MERGE]]:
+; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[P]] to i64
+; CHECK-NEXT: ret i64 [[I]]
+;
+ %a = ptrtoaddr ptr %p to i64
+ br i1 %c, label %then, label %else
+
+then:
+ br label %merge
+
+else:
+ br label %merge
+
+merge:
+ %i = ptrtoint ptr %p to i64
+ ret i64 %i
+}
+
+define i64 @no_transitive_merge_of_ptrtoint_and_ptrtoaddr(ptr %p) {
+; CHECK-LABEL: define i64 @no_transitive_merge_of_ptrtoint_and_ptrtoaddr(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = ptrtoaddr ptr [[P]] to i64
+; CHECK-NEXT: [[ADDA:%.*]] = add i64 [[A]], 7
+; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[P]] to i64
+; CHECK-NEXT: [[ADDI:%.*]] = add i64 [[I]], 7
+; CHECK-NEXT: [[R:%.*]] = add i64 [[ADDA]], [[ADDI]]
+; CHECK-NEXT: ret i64 [[R]]
+;
+ %a = ptrtoaddr ptr %p to i64
+ %adda = add i64 %a, 7
+ %i = ptrtoint ptr %p to i64
+ %addi = add i64 %i, 7
+ %r = add i64 %adda, %addi
+ ret i64 %r
+}
>From b939de6736b44a242601679bf2c9a44b8102c05d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 13 Jul 2026 13:27:56 +0100
Subject: [PATCH 2/3] [GVN] Reuse dominating PtrToInt for PtrToAddr.
A ptrtoaddr and a ptrtoint of the same pointer compute the same value
when the address width equals the pointer representation width. Reuse
a dominating ptrtoint in place of a ptrtoaddr.
This fixes a few end-to-end regressions with
https://github.com/llvm/llvm-project/pull/180244.
I am not sure if there's a better way to implement this. Initially I
tried to use the same numbering for PtrToInt and PtrToAddr, but then
there are multiple places where we need to check the direction is
correct, which seemed a bit more fragile.
---
llvm/lib/Transforms/Scalar/GVN.cpp | 24 ++++++++++++++++++++++++
llvm/test/Transforms/GVN/ptrtoaddr.ll | 3 +--
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 517d33bfba103..91939bb965a5c 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -3400,6 +3400,30 @@ bool GVNPass::processInstruction(Instruction *I) {
return false;
}
+ // A ptrtoaddr and a ptrtoint of the same pointer compute the same value when
+ // the address width equals the pointer representation width. Reuse a
+ // dominating ptrtoint in place of a ptrtoaddr.
+ if (auto *PTA = dyn_cast<PtrToAddrInst>(I)) {
+ const DataLayout &DL = I->getDataLayout();
+ unsigned AS = PTA->getPointerAddressSpace();
+ Value *Ptr = PTA->getPointerOperand();
+ if (DL.getAddressSizeInBits(AS) == DL.getPointerSizeInBits(AS) &&
+ !DL.hasUnstableRepresentation(AS) && Ptr->hasUseList()) {
+ unsigned Scanned = 0;
+ for (User *U : Ptr->users()) {
+ if (++Scanned >= ScanUsersLimit)
+ break;
+ auto *PTI = dyn_cast<PtrToIntInst>(U);
+ if (PTI && PTI->getType() == I->getType() && PTI != I &&
+ DT->dominates(PTI, I)) {
+ patchAndReplaceAllUsesWith(I, PTI);
+ salvageAndRemoveInstruction(I);
+ return true;
+ }
+ }
+ }
+ }
+
// If the number we were assigned was a brand new VN, then we don't
// need to do a lookup to see if the number already exists
// somewhere in the domtree: it can't!
diff --git a/llvm/test/Transforms/GVN/ptrtoaddr.ll b/llvm/test/Transforms/GVN/ptrtoaddr.ll
index 359e16d0c39df..c96961762194e 100644
--- a/llvm/test/Transforms/GVN/ptrtoaddr.ll
+++ b/llvm/test/Transforms/GVN/ptrtoaddr.ll
@@ -33,8 +33,7 @@ define i64 @ptrtoaddr_reuses_dominating_ptrtoint(ptr %p) {
; CHECK-LABEL: define i64 @ptrtoaddr_reuses_dominating_ptrtoint(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[P]] to i64
-; CHECK-NEXT: [[A:%.*]] = ptrtoaddr ptr [[P]] to i64
-; CHECK-NEXT: [[R:%.*]] = add i64 [[I]], [[A]]
+; CHECK-NEXT: [[R:%.*]] = add i64 [[I]], [[I]]
; CHECK-NEXT: ret i64 [[R]]
;
%i = ptrtoint ptr %p to i64
>From 10169d5b2500808a0878c9efb33271f2bd7e9000 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 13 Jul 2026 14:39:02 +0100
Subject: [PATCH 3/3] !fixup lookup value number, thanks
---
llvm/include/llvm/Transforms/Scalar/GVN.h | 1 +
llvm/lib/Transforms/Scalar/GVN.cpp | 31 ++++++++++++-----------
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h
index 0275c01b28020..9142defb34de2 100644
--- a/llvm/include/llvm/Transforms/Scalar/GVN.h
+++ b/llvm/include/llvm/Transforms/Scalar/GVN.h
@@ -222,6 +222,7 @@ class GVNPass : public OptionalPassInfoMixin<GVNPass> {
LLVM_ABI uint32_t lookup(Value *V, bool Verify = true) const;
LLVM_ABI uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred,
Value *LHS, Value *RHS);
+ LLVM_ABI uint32_t lookupPtrToInt(Value *Ptr, Type *Ty);
LLVM_ABI uint32_t phiTranslate(const BasicBlock *BB,
const BasicBlock *PhiBlock, uint32_t Num,
GVNPass &GVN);
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 91939bb965a5c..1b7bcb10be8f8 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -750,6 +750,14 @@ uint32_t GVNPass::ValueTable::lookupOrAddCmp(unsigned Opcode,
return assignExpNewValueNum(Exp).first;
}
+/// Returns the value number of ptrtoint \p Ptr to \Ty.
+uint32_t GVNPass::ValueTable::lookupPtrToInt(Value *Ptr, Type *Ty) {
+ Expression Exp(Instruction::PtrToInt);
+ Exp.Ty = Ty;
+ Exp.VarArgs.push_back(lookupOrAdd(Ptr));
+ return ExpressionNumbering.lookup(Exp);
+}
+
/// Remove all entries from the ValueTable.
void GVNPass::ValueTable::clear() {
ValueNumbering.clear();
@@ -3401,25 +3409,18 @@ bool GVNPass::processInstruction(Instruction *I) {
}
// A ptrtoaddr and a ptrtoint of the same pointer compute the same value when
- // the address width equals the pointer representation width. Reuse a
- // dominating ptrtoint in place of a ptrtoaddr.
+ // the address width equals the pointer representation width.
if (auto *PTA = dyn_cast<PtrToAddrInst>(I)) {
const DataLayout &DL = I->getDataLayout();
unsigned AS = PTA->getPointerAddressSpace();
- Value *Ptr = PTA->getPointerOperand();
if (DL.getAddressSizeInBits(AS) == DL.getPointerSizeInBits(AS) &&
- !DL.hasUnstableRepresentation(AS) && Ptr->hasUseList()) {
- unsigned Scanned = 0;
- for (User *U : Ptr->users()) {
- if (++Scanned >= ScanUsersLimit)
- break;
- auto *PTI = dyn_cast<PtrToIntInst>(U);
- if (PTI && PTI->getType() == I->getType() && PTI != I &&
- DT->dominates(PTI, I)) {
- patchAndReplaceAllUsesWith(I, PTI);
- salvageAndRemoveInstruction(I);
- return true;
- }
+ !DL.hasUnstableRepresentation(AS)) {
+ uint32_t PTINum =
+ VN.lookupPtrToInt(PTA->getPointerOperand(), PTA->getType());
+ if (Value *PTI = findLeader(I->getParent(), PTINum)) {
+ patchAndReplaceAllUsesWith(I, PTI);
+ salvageAndRemoveInstruction(I);
+ return true;
}
}
}
More information about the llvm-commits
mailing list