Skip to content

Commit de9e669

Browse files
nikicdvbuka
authored andcommitted
[InstCombine] Handle ptrtoaddr in gep of pointer sub fold (llvm#164818)
This extends the `ptradd x, ptrtoint(y) - ptrtoint(x)` to `y` InstCombine fold to support ptrtoaddr. In the case where x and y have the same underlying object, this is handled by InstSimplify already. If the underlying object may differ, the replacement can only be performed if provenance does not matter. For pointers with non-address bits we need to be careful here, because the pattern will return a pointer with the non-address bits of x and the address bits of y. As such, uses in ptrtoaddr are safe to replace, but uses in ptrtoint are not. Whether uses in icmp are safe to replace depends on the outcome of the pending discussion on icmp semantics (I'll adjust this in llvm#163936 if/when that lands).
1 parent 86b514d commit de9e669

File tree

2 files changed

+76
-10
lines changed

2 files changed

+76
-10
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3358,21 +3358,21 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
33583358

33593359
if (TyAllocSize == 1) {
33603360
// Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y),
3361-
// but only if the result pointer is only used as if it were an integer,
3362-
// or both point to the same underlying object (otherwise provenance is
3363-
// not necessarily retained).
3361+
// but only if the result pointer is only used as if it were an integer.
3362+
// (The case where the underlying object is the same is handled by
3363+
// InstSimplify.)
33643364
Value *X = GEP.getPointerOperand();
33653365
Value *Y;
3366-
if (match(GEP.getOperand(1),
3367-
m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
3366+
if (match(GEP.getOperand(1), m_Sub(m_PtrToIntOrAddr(m_Value(Y)),
3367+
m_PtrToIntOrAddr(m_Specific(X)))) &&
33683368
GEPType == Y->getType()) {
3369-
bool HasSameUnderlyingObject =
3370-
getUnderlyingObject(X) == getUnderlyingObject(Y);
3369+
bool HasNonAddressBits =
3370+
DL.getAddressSizeInBits(AS) != DL.getPointerSizeInBits(AS);
33713371
bool Changed = false;
33723372
GEP.replaceUsesWithIf(Y, [&](Use &U) {
3373-
bool ShouldReplace = HasSameUnderlyingObject ||
3374-
isa<ICmpInst>(U.getUser()) ||
3375-
isa<PtrToIntInst>(U.getUser());
3373+
bool ShouldReplace = isa<PtrToAddrInst>(U.getUser()) ||
3374+
(!HasNonAddressBits &&
3375+
isa<ICmpInst, PtrToIntInst>(U.getUser()));
33763376
Changed |= ShouldReplace;
33773377
return ShouldReplace;
33783378
});

llvm/test/Transforms/InstCombine/ptrtoaddr.ll

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
; The ptrtoaddr folds are also valid for pointers that have external state.
55
target datalayout = "pe1:64:64:64:32"
66

7+
declare void @use.i1(i1)
8+
declare void @use.i32(i32)
9+
declare void @use.i64(i64)
10+
711
; ptrtoaddr result type is fixed, and can't be combined with integer cast.
812
define i32 @ptrtoaddr_trunc(ptr %p) {
913
; CHECK-LABEL: define i32 @ptrtoaddr_trunc(
@@ -171,3 +175,65 @@ define i128 @sub_zext_ptrtoint_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %offs
171175
%sub = sub i128 %p2.addr.ext, %p.int.ext
172176
ret i128 %sub
173177
}
178+
179+
; The uses in icmp, ptrtoint, ptrtoaddr should be replaced. The one in the
180+
; return value should not, as the provenance differs.
181+
define ptr @gep_sub_ptrtoaddr_different_obj(ptr %p, ptr %p2, ptr %p3) {
182+
; CHECK-LABEL: define ptr @gep_sub_ptrtoaddr_different_obj(
183+
; CHECK-SAME: ptr [[P:%.*]], ptr [[P2:%.*]], ptr [[P3:%.*]]) {
184+
; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr [[P]] to i64
185+
; CHECK-NEXT: [[P2_ADDR:%.*]] = ptrtoaddr ptr [[P2]] to i64
186+
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[P2_ADDR]], [[P_ADDR]]
187+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[SUB]]
188+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P2]], [[P3]]
189+
; CHECK-NEXT: call void @use.i1(i1 [[CMP]])
190+
; CHECK-NEXT: [[INT:%.*]] = ptrtoint ptr [[P2]] to i64
191+
; CHECK-NEXT: call void @use.i64(i64 [[INT]])
192+
; CHECK-NEXT: [[ADDR:%.*]] = ptrtoaddr ptr [[P2]] to i64
193+
; CHECK-NEXT: call void @use.i64(i64 [[ADDR]])
194+
; CHECK-NEXT: ret ptr [[GEP]]
195+
;
196+
%p.addr = ptrtoaddr ptr %p to i64
197+
%p2.addr = ptrtoaddr ptr %p2 to i64
198+
%sub = sub i64 %p2.addr, %p.addr
199+
%gep = getelementptr i8, ptr %p, i64 %sub
200+
%cmp = icmp eq ptr %gep, %p3
201+
call void @use.i1(i1 %cmp)
202+
%int = ptrtoint ptr %gep to i64
203+
call void @use.i64(i64 %int)
204+
%addr = ptrtoaddr ptr %gep to i64
205+
call void @use.i64(i64 %addr)
206+
ret ptr %gep
207+
}
208+
209+
; The use in ptrtoaddr should be replaced. The uses in ptrtoint and icmp should
210+
; not be replaced, as the non-address bits differ. The use in the return value
211+
; should not be replaced as the provenace differs.
212+
define ptr addrspace(1) @gep_sub_ptrtoaddr_different_obj_addrsize(ptr addrspace(1) %p, ptr addrspace(1) %p2, ptr addrspace(1) %p3) {
213+
; CHECK-LABEL: define ptr addrspace(1) @gep_sub_ptrtoaddr_different_obj_addrsize(
214+
; CHECK-SAME: ptr addrspace(1) [[P:%.*]], ptr addrspace(1) [[P2:%.*]], ptr addrspace(1) [[P3:%.*]]) {
215+
; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P]] to i32
216+
; CHECK-NEXT: [[P2_ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P2]] to i32
217+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[P2_ADDR]], [[P_ADDR]]
218+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr addrspace(1) [[P]], i32 [[SUB]]
219+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(1) [[GEP]], [[P3]]
220+
; CHECK-NEXT: call void @use.i1(i1 [[CMP]])
221+
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(1) [[GEP]] to i64
222+
; CHECK-NEXT: [[INT:%.*]] = trunc i64 [[TMP1]] to i32
223+
; CHECK-NEXT: call void @use.i32(i32 [[INT]])
224+
; CHECK-NEXT: [[ADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[P2]] to i32
225+
; CHECK-NEXT: call void @use.i32(i32 [[ADDR]])
226+
; CHECK-NEXT: ret ptr addrspace(1) [[GEP]]
227+
;
228+
%p.addr = ptrtoaddr ptr addrspace(1) %p to i32
229+
%p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32
230+
%sub = sub i32 %p2.addr, %p.addr
231+
%gep = getelementptr i8, ptr addrspace(1) %p, i32 %sub
232+
%cmp = icmp eq ptr addrspace(1) %gep, %p3
233+
call void @use.i1(i1 %cmp)
234+
%int = ptrtoint ptr addrspace(1) %gep to i32
235+
call void @use.i32(i32 %int)
236+
%addr = ptrtoaddr ptr addrspace(1) %gep to i32
237+
call void @use.i32(i32 %addr)
238+
ret ptr addrspace(1) %gep
239+
}

0 commit comments

Comments
 (0)