[llvm] 1b0b59a - [InstComb] Fold inttoptr (add (ptrtoint %B), %O) -> GEP for ICMP users. (#153421)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 21 08:36:28 PDT 2025
Author: Florian Hahn
Date: 2025-08-21T16:36:25+01:00
New Revision: 1b0b59ae4343500d52593c7bd3bce550b3880f7d
URL: https://github.com/llvm/llvm-project/commit/1b0b59ae4343500d52593c7bd3bce550b3880f7d
DIFF: https://github.com/llvm/llvm-project/commit/1b0b59ae4343500d52593c7bd3bce550b3880f7d.diff
LOG: [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
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
llvm/test/Transforms/InstCombine/fold-bin-operand.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 801ac00fa8fa8..6ef55d4bfc7d7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -2072,6 +2072,19 @@ Instruction *InstCombinerImpl::visitIntToPtr(IntToPtrInst &CI) {
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))
return I;
diff --git a/llvm/test/Transforms/InstCombine/fold-bin-operand.ll b/llvm/test/Transforms/InstCombine/fold-bin-operand.ll
index 45d09f41fb4c5..79671215dba61 100644
--- a/llvm/test/Transforms/InstCombine/fold-bin-operand.ll
+++ b/llvm/test/Transforms/InstCombine/fold-bin-operand.ll
@@ -32,10 +32,8 @@ define i32 @g(i32 %x) {
define i1 @inttoptr_add_ptrtoint_used_by_single_icmp(ptr %src, ptr %p2) {
; CHECK-LABEL: @inttoptr_add_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: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
+; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%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) {
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_operands_swapped(
-; 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: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
+; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%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) {
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset(
-; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
-; CHECK-NEXT: [[A:%.*]] = add i64 [[OFF:%.*]], [[I]]
-; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
-; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%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) {
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_constant_offset_operands_swapped(
-; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[SRC:%.*]] to i64
-; CHECK-NEXT: [[A:%.*]] = add i64 [[OFF:%.*]], [[I]]
-; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[A]] to ptr
-; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%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
}
+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) {
; CHECK-LABEL: @multiple_inttoptr_add_ptrtoint_used_by_single_icmp(
; CHECK-NEXT: ret i1 false
@@ -181,10 +190,8 @@ define i1 @inttoptr_add_ptrtoint_used_by_single_icmp_in_
diff erent_bb(i1 %bc, ptr
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_single_icmp_in_
diff erent_bb(
; CHECK-NEXT: br i1 [[BC:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
-; 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: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
+; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
; CHECK-NEXT: ret i1 [[C]]
; CHECK: else:
; 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) {
; CHECK-LABEL: @inttoptr_add_ptrtoint_used_by_multiple_icmps(
-; 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_1:%.*]] = icmp eq ptr [[P2:%.*]], [[P]]
-; CHECK-NEXT: [[C_2:%.*]] = icmp eq ptr [[P3:%.*]], [[P]]
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 10
+; CHECK-NEXT: [[C_1:%.*]] = icmp eq ptr [[P2]], [[P:%.*]]
+; CHECK-NEXT: [[C_2:%.*]] = icmp eq ptr [[P2]], [[P3:%.*]]
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[C_1]], [[C_2]]
; 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 @bar(i64)
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(
More information about the llvm-commits
mailing list