[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: https://github.com/llvm/llvm-project/pull/153421
This commit is contained in:
parent
0594bad039
commit
1b0b59ae43
@ -2072,6 +2072,19 @@ Instruction *InstCombinerImpl::visitIntToPtr(IntToPtrInst &CI) {
|
|||||||
return new IntToPtrInst(P, CI.getType());
|
return new IntToPtrInst(P, CI.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace (inttoptr (add (ptrtoint %Base), %Offset)) with
|
||||||
|
// (getelementptr i8, %Base, %Offset) if all users are ICmps.
|
||||||
|
Value *Base;
|
||||||
|
Value *Offset;
|
||||||
|
if (match(CI.getOperand(0),
|
||||||
|
m_OneUse(m_c_Add(m_PtrToIntSameSize(DL, m_Value(Base)),
|
||||||
|
m_Value(Offset)))) &&
|
||||||
|
CI.getType()->getPointerAddressSpace() ==
|
||||||
|
Base->getType()->getPointerAddressSpace() &&
|
||||||
|
all_of(CI.users(), IsaPred<ICmpInst>)) {
|
||||||
|
return GetElementPtrInst::Create(Builder.getInt8Ty(), Base, Offset);
|
||||||
|
}
|
||||||
|
|
||||||
if (Instruction *I = commonCastTransforms(CI))
|
if (Instruction *I = commonCastTransforms(CI))
|
||||||
return I;
|
return I;
|
||||||
|
|
||||||
|
@ -32,10 +32,8 @@ define i32 @g(i32 %x) {
|
|||||||
|
|
||||||
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
|
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
|
||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp(
|
||||||
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
|
||||||
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
|
||||||
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
|
||||||
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: ret i1 [[C]]
|
; CHECK-NEXT: ret i1 [[C]]
|
||||||
;
|
;
|
||||||
%i = ptrtoint ptr %src to i64
|
%i = ptrtoint ptr %src to i64
|
||||||
@ -47,10 +45,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
|
|||||||
|
|
||||||
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(ptr %src, ptr %p2) {
|
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(ptr %src, ptr %p2) {
|
||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(
|
||||||
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
|
||||||
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
|
||||||
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
|
||||||
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: ret i1 [[C]]
|
; CHECK-NEXT: ret i1 [[C]]
|
||||||
;
|
;
|
||||||
%i = ptrtoint ptr %src to i64
|
%i = ptrtoint ptr %src to i64
|
||||||
@ -62,10 +58,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(ptr %src,
|
|||||||
|
|
||||||
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(ptr %src, i64 %off, ptr %p2) {
|
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(ptr %src, i64 %off, ptr %p2) {
|
||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(
|
||||||
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[OFF:%.*]]
|
||||||
; CHECK-NEXT: [[A:%.*]] = add i64 [[OFF:%.*]], [[I]]
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
|
||||||
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
|
||||||
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: ret i1 [[C]]
|
; CHECK-NEXT: ret i1 [[C]]
|
||||||
;
|
;
|
||||||
%i = ptrtoint ptr %src to i64
|
%i = ptrtoint ptr %src to i64
|
||||||
@ -77,10 +71,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(ptr %src, i
|
|||||||
|
|
||||||
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(ptr %src, i64 %off, ptr %p2) {
|
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(ptr %src, i64 %off, ptr %p2) {
|
||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(
|
||||||
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[OFF:%.*]]
|
||||||
; CHECK-NEXT: [[A:%.*]] = add i64 [[OFF:%.*]], [[I]]
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
|
||||||
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
|
||||||
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: ret i1 [[C]]
|
; CHECK-NEXT: ret i1 [[C]]
|
||||||
;
|
;
|
||||||
%i = ptrtoint ptr %src to i64
|
%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
|
|||||||
ret i1 %c
|
ret i1 %c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i1 @inttoptr_add_multiple_users_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
|
||||||
|
; CHECK-LABEL: @inttoptr_add_multiple_users_ptrtoint_used_by_single_icmp(
|
||||||
|
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
||||||
|
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
|
||||||
|
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
||||||
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
||||||
|
; CHECK-NEXT: call void @bar(i64 [[A]])
|
||||||
|
; CHECK-NEXT: ret i1 [[C]]
|
||||||
|
;
|
||||||
|
%i = ptrtoint ptr %src to i64
|
||||||
|
%a = add i64 %i, 10
|
||||||
|
%p = inttoptr i64 %a to ptr
|
||||||
|
%c = icmp eq ptr %p, %p2
|
||||||
|
call void @bar(i64 %a)
|
||||||
|
ret i1 %c
|
||||||
|
}
|
||||||
|
|
||||||
define i1 @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src) {
|
define i1 @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src) {
|
||||||
; CHECK-LABEL: @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(
|
; CHECK-LABEL: @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(
|
||||||
; CHECK-NEXT: ret i1 false
|
; CHECK-NEXT: ret i1 false
|
||||||
@ -181,10 +190,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_in_different_bb(i1 %bc, ptr
|
|||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_in_different_bb(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_in_different_bb(
|
||||||
; CHECK-NEXT: br i1 [[BC:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
; CHECK-NEXT: br i1 [[BC:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
||||||
; CHECK: then:
|
; CHECK: then:
|
||||||
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
|
||||||
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
|
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
|
||||||
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
|
||||||
; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: ret i1 [[C]]
|
; CHECK-NEXT: ret i1 [[C]]
|
||||||
; CHECK: else:
|
; CHECK: else:
|
||||||
; CHECK-NEXT: ret i1 false
|
; CHECK-NEXT: ret i1 false
|
||||||
@ -204,11 +211,9 @@ else:
|
|||||||
|
|
||||||
define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps(ptr %src, ptr %p2, ptr %p3) {
|
define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps(ptr %src, ptr %p2, ptr %p3) {
|
||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps(
|
||||||
; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
|
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
|
||||||
; CHECK-NEXT: [[A:%.*]] = add i64 [[I]], 10
|
; CHECK-NEXT: [[C_1:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
|
||||||
; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
|
; CHECK-NEXT: [[C_2:%.*]] = icmp eq ptr [[P2]], [[P3:%.*]]
|
||||||
; CHECK-NEXT: [[C_1:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: [[C_2:%.*]] = icmp eq ptr [[P3:%.*]], [[P]]
|
|
||||||
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[C_1]], [[C_2]]
|
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[C_1]], [[C_2]]
|
||||||
; CHECK-NEXT: ret i1 [[XOR]]
|
; CHECK-NEXT: ret i1 [[XOR]]
|
||||||
;
|
;
|
||||||
@ -222,6 +227,7 @@ define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps(ptr %src, ptr %p2, ptr %
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare void @foo(ptr)
|
declare void @foo(ptr)
|
||||||
|
declare void @bar(i64)
|
||||||
|
|
||||||
define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps_and_other_user(ptr %src, ptr %p2, ptr %p3) {
|
define i1 @inttoptr_add_ptrtoint_used_by_multiple_icmps_and_other_user(ptr %src, ptr %p2, ptr %p3) {
|
||||||
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps_and_other_user(
|
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps_and_other_user(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user