[llvm] [GVN] Reuse dominating PtrToInt for PtrToAddr. (PR #209164)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 05:42:53 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/209164

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.

>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/2] [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/2] [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



More information about the llvm-commits mailing list