[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