[InstSimplify] Support ptrtoaddr in simplifyICmpInst() (#171985)

This is basically the same change as #162653, but for InstSimplify
instead of ConstantFolding.

It folds `icmp (ptrtoaddr x, ptrtoaddr y)` to `icmp (x, y)` and `icmp
(ptrtoaddr x, C)` to `icmp (x, inttoptr C)`.

The fold is restricted to the case where the result type is the address
type, as icmp only compares the icmp bits. As in the other PR, I think
in practice all the folds are also going to work if the ptrtoint result
type is larger than the address size, but it's unclear how to justify
this in general.
This commit is contained in:
Nikita Popov
2025-12-15 10:06:28 +01:00
committed by GitHub
parent 37c7f695dc
commit 80b900e91c
2 changed files with 79 additions and 5 deletions

View File

@@ -3847,17 +3847,19 @@ static Value *simplifyICmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
Type *SrcTy = SrcOp->getType();
Type *DstTy = LI->getType();
// Turn icmp (ptrtoint x), (ptrtoint/constant) into a compare of the input
// if the integer type is the same size as the pointer type.
if (MaxRecurse && isa<PtrToIntInst>(LI) &&
Q.DL.getTypeSizeInBits(SrcTy) == DstTy->getPrimitiveSizeInBits()) {
// Turn icmp (ptrtoint/ptrtoaddr x), (ptrtoint/ptrtoaddr/constant) into a
// compare of the input if the integer type is the same size as the
// pointer address type (icmp only compares the address of the pointer).
if (MaxRecurse && (isa<PtrToIntInst, PtrToAddrInst>(LI)) &&
Q.DL.getAddressType(SrcTy) == DstTy) {
if (Constant *RHSC = dyn_cast<Constant>(RHS)) {
// Transfer the cast to the constant.
if (Value *V = simplifyICmpInst(Pred, SrcOp,
ConstantExpr::getIntToPtr(RHSC, SrcTy),
Q, MaxRecurse - 1))
return V;
} else if (PtrToIntInst *RI = dyn_cast<PtrToIntInst>(RHS)) {
} else if (isa<PtrToIntInst, PtrToAddrInst>(RHS)) {
auto *RI = cast<CastInst>(RHS);
if (RI->getOperand(0)->getType() == SrcTy)
// Compare without the cast.
if (Value *V = simplifyICmpInst(Pred, SrcOp, RI->getOperand(0), Q,

View File

@@ -398,3 +398,75 @@ define i1 @icmp_relational_ptrtoint_ptrtoint_addrsize() {
%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
}
define i1 @icmp_ptrtoaddr_ptrtoaddr_dyn(ptr %a) {
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_ptrtoaddr_dyn(
; CHECK-SAME: ptr [[A:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%gep = getelementptr i8, ptr %a, i64 1
%a.addr = ptrtoaddr ptr %a to i64
%gep.addr = ptrtoaddr ptr %gep to i64
%cmp = icmp ne i64 %a.addr, %gep.addr
ret i1 %cmp
}
define i1 @icmp_ptrtoaddr_ptrtoaddr_dyn_addrsize(ptr addrspace(1) %a) {
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_ptrtoaddr_dyn_addrsize(
; CHECK-SAME: ptr addrspace(1) [[A:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%gep = getelementptr i8, ptr addrspace(1) %a, i32 1
%a.addr = ptrtoaddr ptr addrspace(1) %a to i32
%gep.addr = ptrtoaddr ptr addrspace(1) %gep to i32
%cmp = icmp ne i32 %a.addr, %gep.addr
ret i1 %cmp
}
; This could still be folded, because the non-address bits being non-equal
; implies that all bits taken together are also non-equal.
define i1 @icmp_ptrtoint_ptrtoint_dyn_addrsize(ptr addrspace(1) %a) {
; CHECK-LABEL: define i1 @icmp_ptrtoint_ptrtoint_dyn_addrsize(
; CHECK-SAME: ptr addrspace(1) [[A:%.*]]) {
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr addrspace(1) [[A]], i32 1
; CHECK-NEXT: [[A_ADDR:%.*]] = ptrtoint ptr addrspace(1) [[A]] to i64
; CHECK-NEXT: [[GEP_ADDR:%.*]] = ptrtoint ptr addrspace(1) [[GEP]] to i64
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[A_ADDR]], [[GEP_ADDR]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%gep = getelementptr i8, ptr addrspace(1) %a, i32 1
%a.addr = ptrtoint ptr addrspace(1) %a to i64
%gep.addr = ptrtoint ptr addrspace(1) %gep to i64
%cmp = icmp ne i64 %a.addr, %gep.addr
ret i1 %cmp
}
define i1 @icmp_ptrtoaddr_null_dyn(ptr nonnull %a) {
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_null_dyn(
; CHECK-SAME: ptr nonnull [[A:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%a.addr = ptrtoaddr ptr %a to i64
%cmp = icmp ne i64 %a.addr, 0
ret i1 %cmp
}
define i1 @icmp_ptrtoaddr_null_dyn_addrsize(ptr addrspace(1) nonnull %a) {
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_null_dyn_addrsize(
; CHECK-SAME: ptr addrspace(1) nonnull [[A:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%a.addr = ptrtoaddr ptr addrspace(1) %a to i32
%cmp = icmp ne i32 %a.addr, 0
ret i1 %cmp
}
define i1 @icmp_ptrtoint_null_dyn_addrsize(ptr addrspace(1) nonnull %a) {
; CHECK-LABEL: define i1 @icmp_ptrtoint_null_dyn_addrsize(
; CHECK-SAME: ptr addrspace(1) nonnull [[A:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%a.addr = ptrtoint ptr addrspace(1) %a to i64
%cmp = icmp ne i64 %a.addr, 0
ret i1 %cmp
}