Skip to content

Commit 1b0b59a

Browse files
authored
[InstComb] Fold inttoptr (add (ptrtoint %B), %O) -> GEP for ICMP users. (#153421)
Replace inttoptr (add (ptrtoint %B), %O) with (getelementptr i8, %B, %o) if all users are ICmp instruction, which in turn means only the address value is compared. We should be able to do this, if the src pointer, the integer type and the destination pointer types have the same bitwidth and address space. A common source of such (inttoptr (add (ptrtoint %B), %O)) is from various iterations in libc++. In practice this triggers in a number of files in Clang and various open source projects, including cppcheck, diamond, llama and more. Alive2 Proof with constant offset: https://alive2.llvm.org/ce/z/K_5N_B PR: #153421
1 parent 0594bad commit 1b0b59a

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-25
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,19 @@ Instruction *InstCombinerImpl::visitIntToPtr(IntToPtrInst &CI) {
20722072
return new IntToPtrInst(P, CI.getType());
20732073
}
20742074

2075+
// Replace (inttoptr (add (ptrtoint %Base), %Offset)) with
2076+
// (getelementptr i8, %Base, %Offset) if all users are ICmps.
2077+
Value *Base;
2078+
Value *Offset;
2079+
if (match(CI.getOperand(0),
2080+
m_OneUse(m_c_Add(m_PtrToIntSameSize(DL, m_Value(Base)),
2081+
m_Value(Offset)))) &&
2082+
CI.getType()->getPointerAddressSpace() ==
2083+
Base->getType()->getPointerAddressSpace() &&
2084+
all_of(CI.users(), IsaPred<ICmpInst>)) {
2085+
return GetElementPtrInst::Create(Builder.getInt8Ty(), Base, Offset);
2086+
}
2087+
20752088
if (Instruction *I = commonCastTransforms(CI))
20762089
return I;
20772090

llvm/test/Transforms/InstCombine/fold-bin-operand.ll

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ define i32 @g(i32 %x) {
3232

3333
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
3434
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp(
35-
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
36-
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
37-
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
38-
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
35+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
36+
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
3937
; CHECK-NEXT: ret i1 [[C]]
4038
;
4139
%i = ptrtoint ptr %src to i64
@@ -47,10 +45,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
4745

4846
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(ptr %src, ptr %p2) {
4947
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(
50-
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
51-
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
52-
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
53-
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
48+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
49+
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
5450
; CHECK-NEXT: ret i1 [[C]]
5551
;
5652
%i = ptrtoint ptr %src to i64
@@ -62,10 +58,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(ptr %src,
6258

6359
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(ptr %src, i64 %off, ptr %p2) {
6460
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(
65-
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
66-
; CHECK-NEXT: [[A:%.*]] = add i64 [[OFF:%.*]], [[I]]
67-
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
68-
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
61+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[OFF:%.*]]
62+
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
6963
; CHECK-NEXT: ret i1 [[C]]
7064
;
7165
%i = ptrtoint ptr %src to i64
@@ -77,10 +71,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(ptr %src, i
7771

7872
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(ptr %src, i64 %off, ptr %p2) {
7973
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(
80-
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
81-
; CHECK-NEXT: [[A:%.*]] = add i64 [[OFF:%.*]], [[I]]
82-
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
83-
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
74+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[OFF:%.*]]
75+
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
8476
; CHECK-NEXT: ret i1 [[C]]
8577
;
8678
%i = ptrtoint ptr %src to i64
@@ -137,6 +129,23 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_int_type_does_not_match_ptr
137129
ret i1 %c
138130
}
139131

132+
define i1 @inttoptr_add_multiple_users_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
133+
; CHECK-LABEL: @inttoptr_add_multiple_users_ptrtoint_used_by_single_icmp(
134+
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
135+
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
136+
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
137+
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
138+
; CHECK-NEXT: call void @bar(i64 [[A]])
139+
; CHECK-NEXT: ret i1 [[C]]
140+
;
141+
%i = ptrtoint ptr %src to i64
142+
%a = add i64 %i, 10
143+
%p = inttoptr i64 %a to ptr
144+
%c = icmp eq ptr %p, %p2
145+
call void @bar(i64 %a)
146+
ret i1 %c
147+
}
148+
140149
define i1 @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src) {
141150
; CHECK-LABEL: @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(
142151
; CHECK-NEXT: ret i1 false
@@ -181,10 +190,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_in_different_bb(i1 %bc, ptr
181190
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_in_different_bb(
182191
; CHECK-NEXT: br i1 [[BC:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
183192
; CHECK: then:
184-
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
185-
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
186-
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
187-
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
193+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
194+
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
188195
; CHECK-NEXT: ret i1 [[C]]
189196
; CHECK: else:
190197
; CHECK-NEXT: ret i1 false
@@ -204,11 +211,9 @@ else:
204211

205212
define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps(ptr %src, ptr %p2, ptr %p3) {
206213
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps(
207-
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
208-
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
209-
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
210-
; CHECK-NEXT: [[C_1:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
211-
; CHECK-NEXT: [[C_2:%.*]] = icmp eq ptr [[P3:%.*]], [[P]]
214+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
215+
; CHECK-NEXT: [[C_1:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
216+
; CHECK-NEXT: [[C_2:%.*]] = icmp eq ptr [[P2]], [[P3:%.*]]
212217
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[C_1]], [[C_2]]
213218
; CHECK-NEXT: ret i1 [[XOR]]
214219
;
@@ -222,6 +227,7 @@ define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps(ptr %src, ptr %p2, ptr %
222227
}
223228

224229
declare void @foo(ptr)
230+
declare void @bar(i64)
225231

226232
define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps_and_other_user(ptr %src, ptr %p2, ptr %p3) {
227233
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps_and_other_user(

0 commit comments

Comments
 (0)