[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