Skip to content

Commit 6a25e45

Browse files
authored
[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 #163936.
1 parent c9648d7 commit 6a25e45

File tree

2 files changed

+94
-10
lines changed

2 files changed

+94
-10
lines changed

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,11 +1223,12 @@ Constant *llvm::ConstantFoldCompareInstOperands(
12231223
}
12241224
}
12251225

1226-
// Only do this transformation if the int is intptrty in size, otherwise
1227-
// there is a truncation or extension that we aren't modeling.
1228-
if (CE0->getOpcode() == Instruction::PtrToInt) {
1229-
Type *IntPtrTy = DL.getIntPtrType(CE0->getOperand(0)->getType());
1230-
if (CE0->getType() == IntPtrTy) {
1226+
// icmp only compares the address part of the pointer, so only do this
1227+
// transform if the integer size matches the address size.
1228+
if (CE0->getOpcode() == Instruction::PtrToInt ||
1229+
CE0->getOpcode() == Instruction::PtrToAddr) {
1230+
Type *AddrTy = DL.getAddressType(CE0->getOperand(0)->getType());
1231+
if (CE0->getType() == AddrTy) {
12311232
Constant *C = CE0->getOperand(0);
12321233
Constant *Null = Constant::getNullValue(C->getType());
12331234
return ConstantFoldCompareInstOperands(Predicate, C, Null, DL, TLI);
@@ -1250,11 +1251,12 @@ Constant *llvm::ConstantFoldCompareInstOperands(
12501251
return ConstantFoldCompareInstOperands(Predicate, C0, C1, DL, TLI);
12511252
}
12521253

1253-
// Only do this transformation if the int is intptrty in size, otherwise
1254-
// there is a truncation or extension that we aren't modeling.
1255-
if (CE0->getOpcode() == Instruction::PtrToInt) {
1256-
Type *IntPtrTy = DL.getIntPtrType(CE0->getOperand(0)->getType());
1257-
if (CE0->getType() == IntPtrTy &&
1254+
// icmp only compares the address part of the pointer, so only do this
1255+
// transform if the integer size matches the address size.
1256+
if (CE0->getOpcode() == Instruction::PtrToInt ||
1257+
CE0->getOpcode() == Instruction::PtrToAddr) {
1258+
Type *AddrTy = DL.getAddressType(CE0->getOperand(0)->getType());
1259+
if (CE0->getType() == AddrTy &&
12581260
CE0->getOperand(0)->getType() == CE1->getOperand(0)->getType()) {
12591261
return ConstantFoldCompareInstOperands(
12601262
Predicate, CE0->getOperand(0), CE1->getOperand(0), DL, TLI);

llvm/test/Transforms/InstSimplify/ptrtoaddr.ll

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,85 @@ define ptr @gep_gep_inv_ptrtoaddr(ptr %p) {
316316
%gep2 = getelementptr i8, ptr %gep1, i64 %p.addr.inv
317317
ret ptr %gep2
318318
}
319+
320+
define i1 @icmp_ptrtoaddr_0() {
321+
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_0() {
322+
; CHECK-NEXT: ret i1 true
323+
;
324+
%cmp = icmp ne i64 ptrtoaddr (ptr @g to i64), 0
325+
ret i1 %cmp
326+
}
327+
328+
; This fails to fold because we currently don't assume that globals are located
329+
; at a non-null address for non-default address spaces.
330+
define i1 @icmp_ptrtoaddr_0_addrsize() {
331+
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_0_addrsize() {
332+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), 0
333+
; CHECK-NEXT: ret i1 [[CMP]]
334+
;
335+
%cmp = icmp ne i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), 0
336+
ret i1 %cmp
337+
}
338+
339+
define i1 @icmp_ptrtoint_0_addrsize() {
340+
; CHECK-LABEL: define i1 @icmp_ptrtoint_0_addrsize() {
341+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), 0
342+
; CHECK-NEXT: ret i1 [[CMP]]
343+
;
344+
%cmp = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), 0
345+
ret i1 %cmp
346+
}
347+
348+
define i1 @icmp_ptrtoaddr_ptrtoaddr() {
349+
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_ptrtoaddr() {
350+
; CHECK-NEXT: ret i1 true
351+
;
352+
%cmp = icmp ne i64 ptrtoaddr (ptr @g to i64), ptrtoaddr (ptr @g2 to i64)
353+
ret i1 %cmp
354+
}
355+
356+
define i1 @icmp_ptrtoaddr_ptrtoaddr_addrsize() {
357+
; CHECK-LABEL: define i1 @icmp_ptrtoaddr_ptrtoaddr_addrsize() {
358+
; CHECK-NEXT: ret i1 true
359+
;
360+
%cmp = icmp ne i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), ptrtoaddr (ptr addrspace(1) @g2.as1 to i32)
361+
ret i1 %cmp
362+
}
363+
364+
; This could still be folded because the address being non-equal also implies
365+
; that all pointer bits together are non-equal.
366+
define i1 @icmp_ptrtoint_ptrtoint_addrsize() {
367+
; CHECK-LABEL: define i1 @icmp_ptrtoint_ptrtoint_addrsize() {
368+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), ptrtoint (ptr addrspace(1) @g2.as1 to i64)
369+
; CHECK-NEXT: ret i1 [[CMP]]
370+
;
371+
%cmp = icmp ne i64 ptrtoint (ptr addrspace(1) @g.as1 to i64), ptrtoint (ptr addrspace(1) @g2.as1 to i64)
372+
ret i1 %cmp
373+
}
374+
375+
define i1 @icmp_relational_ptrtoaddr_ptrtoaddr() {
376+
; CHECK-LABEL: define i1 @icmp_relational_ptrtoaddr_ptrtoaddr() {
377+
; CHECK-NEXT: ret i1 true
378+
;
379+
%cmp = icmp ult i64 ptrtoaddr (ptr @g to i64), ptrtoaddr (ptr getelementptr inbounds (i8, ptr @g, i64 1) to i64)
380+
ret i1 %cmp
381+
}
382+
383+
define i1 @icmp_relational_ptrtoaddr_ptrtoaddr_addrsize() {
384+
; CHECK-LABEL: define i1 @icmp_relational_ptrtoaddr_ptrtoaddr_addrsize() {
385+
; CHECK-NEXT: ret i1 true
386+
;
387+
%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)
388+
ret i1 %cmp
389+
}
390+
391+
; This could still be folded because we know that the non-address bits must be
392+
; the same, as GEP does not modify them.
393+
define i1 @icmp_relational_ptrtoint_ptrtoint_addrsize() {
394+
; CHECK-LABEL: define i1 @icmp_relational_ptrtoint_ptrtoint_addrsize() {
395+
; 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)
396+
; CHECK-NEXT: ret i1 [[CMP]]
397+
;
398+
%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)
399+
ret i1 %cmp
400+
}

0 commit comments

Comments
 (0)