[llvm] 6a25e45 - [ConstantFolding] Support ptrtoaddr in ConstantFoldCompareInstOperands (#162653)

via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 10 23:14:48 PST 2025


Author: Nikita Popov
Date: 2025-12-11T08:14:44+01:00
New Revision: 6a25e454d6443a518e1460a9125ed60d0470fe83

URL: https://github.com/llvm/llvm-project/commit/6a25e454d6443a518e1460a9125ed60d0470fe83
DIFF: https://github.com/llvm/llvm-project/commit/6a25e454d6443a518e1460a9125ed60d0470fe83.diff

LOG: [ConstantFolding] Support ptrtoaddr in ConstantFoldCompareInstOperands (#162653)

This folds `icmp (ptrtoaddr x, ptrtoaddr y)` to `icmp (x, y)`, matching
the existing ptrtoint fold. Restrict both folds to only the case where
the result type matches the address type.
    
I think that all folds this can do in practice end up actually being
valid for ptrtoint to a type large than the address size as well, but I
don't really see a way to justify this generically without making
assumptions about what kind of folding the recursive calls may do.

This is based on the icmp semantics specified in
https://github.com/llvm/llvm-project/pull/163936.

Added: 
    

Modified: 
    llvm/lib/Analysis/ConstantFolding.cpp
    llvm/test/Transforms/InstSimplify/ptrtoaddr.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index b39b32042dd2f..a9b51065a1d99 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1223,11 +1223,12 @@ Constant *llvm::ConstantFoldCompareInstOperands(
         }
       }
 
-      // Only do this transformation if the int is intptrty in size, otherwise
-      // there is a truncation or extension that we aren't modeling.
-      if (CE0->getOpcode() == Instruction::PtrToInt) {
-        Type *IntPtrTy = DL.getIntPtrType(CE0->getOperand(0)->getType());
-        if (CE0->getType() == IntPtrTy) {
+      // icmp only compares the address part of the pointer, so only do this
+      // transform if the integer size matches the address size.
+      if (CE0->getOpcode() == Instruction::PtrToInt ||
+          CE0->getOpcode() == Instruction::PtrToAddr) {
+        Type *AddrTy = DL.getAddressType(CE0->getOperand(0)->getType());
+        if (CE0->getType() == AddrTy) {
           Constant *C = CE0->getOperand(0);
           Constant *Null = Constant::getNullValue(C->getType());
           return ConstantFoldCompareInstOperands(Predicate, C, Null, DL, TLI);
@@ -1250,11 +1251,12 @@ Constant *llvm::ConstantFoldCompareInstOperands(
             return ConstantFoldCompareInstOperands(Predicate, C0, C1, DL, TLI);
         }
 
-        // Only do this transformation if the int is intptrty in size, otherwise
-        // there is a truncation or extension that we aren't modeling.
-        if (CE0->getOpcode() == Instruction::PtrToInt) {
-          Type *IntPtrTy = DL.getIntPtrType(CE0->getOperand(0)->getType());
-          if (CE0->getType() == IntPtrTy &&
+        // icmp only compares the address part of the pointer, so only do this
+        // transform if the integer size matches the address size.
+        if (CE0->getOpcode() == Instruction::PtrToInt ||
+            CE0->getOpcode() == Instruction::PtrToAddr) {
+          Type *AddrTy = DL.getAddressType(CE0->getOperand(0)->getType());
+          if (CE0->getType() == AddrTy &&
               CE0->getOperand(0)->getType() == CE1->getOperand(0)->getType()) {
             return ConstantFoldCompareInstOperands(
                 Predicate, CE0->getOperand(0), CE1->getOperand(0), DL, TLI);

diff  --git a/llvm/test/Transforms/InstSimplify/ptrtoaddr.ll b/llvm/test/Transforms/InstSimplify/ptrtoaddr.ll
index d06b520931b92..eaccf15cd80f6 100644
--- a/llvm/test/Transforms/InstSimplify/ptrtoaddr.ll
+++ b/llvm/test/Transforms/InstSimplify/ptrtoaddr.ll
@@ -316,3 +316,85 @@ define ptr @gep_gep_inv_ptrtoaddr(ptr %p) {
   %gep2 = getelementptr i8, ptr %gep1, i64 %p.addr.inv
   ret ptr %gep2
 }
+
+define i1 @icmp_ptrtoaddr_0() {
+; CHECK-LABEL: define i1 @icmp_ptrtoaddr_0() {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp ne i64 ptrtoaddr (ptr @g to i64), 0
+  ret i1 %cmp
+}
+
+; This fails to fold because we currently don't assume that globals are located
+; at a non-null address for non-default address spaces.
+define i1 @icmp_ptrtoaddr_0_addrsize() {
+; CHECK-LABEL: define i1 @icmp_ptrtoaddr_0_addrsize() {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp ne i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_ptrtoint_0_addrsize() {
+; CHECK-LABEL: define i1 @icmp_ptrtoint_0_addrsize() {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), 0
+  ret i1 %cmp
+}
+
+define i1 @icmp_ptrtoaddr_ptrtoaddr() {
+; CHECK-LABEL: define i1 @icmp_ptrtoaddr_ptrtoaddr() {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp ne i64 ptrtoaddr (ptr @g to i64), ptrtoaddr (ptr @g2 to i64)
+  ret i1 %cmp
+}
+
+define i1 @icmp_ptrtoaddr_ptrtoaddr_addrsize() {
+; CHECK-LABEL: define i1 @icmp_ptrtoaddr_ptrtoaddr_addrsize() {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp ne i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), ptrtoaddr (ptr addrspace(1) @g2.as1 to i32)
+  ret i1 %cmp
+}
+
+; This could still be folded because the address being non-equal also implies
+; that all pointer bits together are non-equal.
+define i1 @icmp_ptrtoint_ptrtoint_addrsize() {
+; CHECK-LABEL: define i1 @icmp_ptrtoint_ptrtoint_addrsize() {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), ptrtoint (ptr addrspace(1) @g2.as1 to i64)
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), ptrtoint (ptr addrspace(1) @g2.as1 to i64)
+  ret i1 %cmp
+}
+
+define i1 @icmp_relational_ptrtoaddr_ptrtoaddr() {
+; CHECK-LABEL: define i1 @icmp_relational_ptrtoaddr_ptrtoaddr() {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp ult i64 ptrtoaddr (ptr @g to i64), ptrtoaddr (ptr getelementptr inbounds (i8, ptr @g, i64 1) to i64)
+  ret i1 %cmp
+}
+
+define i1 @icmp_relational_ptrtoaddr_ptrtoaddr_addrsize() {
+; CHECK-LABEL: define i1 @icmp_relational_ptrtoaddr_ptrtoaddr_addrsize() {
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp ult i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), ptrtoaddr (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) @g.as1, i32 1) to i32)
+  ret i1 %cmp
+}
+
+; This could still be folded because we know that the non-address bits must be
+; the same, as GEP does not modify them.
+define i1 @icmp_relational_ptrtoint_ptrtoint_addrsize() {
+; CHECK-LABEL: define i1 @icmp_relational_ptrtoint_ptrtoint_addrsize() {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) @g.as1, i64 1) to i64)
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %cmp = icmp ult i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) @g.as1, i64 1) to i64)
+  ret i1 %cmp
+}


        


More information about the llvm-commits mailing list