-
Notifications
You must be signed in to change notification settings - Fork 10.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstCombine] Fold pointer adding in integer to arithmetic add #91596
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Monad (YanWQ-monad) ChangesFold define i32 @<!-- -->src(i32 %x, i32 %y) {
%base = inttoptr i32 %x to ptr
%ptr = getelementptr inbounds i8, ptr %base, i32 %y
%r = ptrtoint ptr %ptr to i32
ret i32 %r
} where both define i32 @<!-- -->tgt(i32 %x, i32 %y) {
%r = add nuw i32 %x, %y
ret i32 %r
} MotivationIt seems unnecessary to convert %conv.i188 = zext i32 %145 to i64
%add.i189 = add i64 %conv.i188, %125
%146 = load i16, ptr %num_aux_entries10.i, align 2
%conv2.i191 = zext i16 %146 to i64
%mul.i192 = shl nuw nsw i64 %conv2.i191, 3
%add3.i193 = add i64 %add.i189, %mul.i192
%147 = inttoptr i64 %add3.i193 to ptr
%sub.ptr.lhs.cast.i195 = ptrtoint ptr %144 to i64
%sub.ptr.rhs.cast.i196 = ptrtoint ptr %143 to i64
%sub.ptr.sub.i197 = sub i64 %sub.ptr.lhs.cast.i195, %sub.ptr.rhs.cast.i196
%add.ptr = getelementptr inbounds i8, ptr %147, i64 %sub.ptr.sub.i197
%sub.ptr.lhs.cast = ptrtoint ptr %add.ptr to i64
%sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %125 where But this fold involves Full diff: https://github.com/llvm/llvm-project/pull/91596.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 11e31877de38..18ad8706f884 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -2073,6 +2073,16 @@ Instruction *InstCombinerImpl::visitPtrToInt(PtrToIntInst &CI) {
return InsertElementInst::Create(Vec, NewCast, Index);
}
+ // (ptrtoint (gep (inttoptr Base), Offset)) -> Base + Offset
+ Value *Base, *Offset;
+ if (match(SrcOp, m_OneUse(m_PtrAdd(m_OneUse(m_IntToPtr(m_Value(Base))),
+ m_Value(Offset)))) &&
+ Base->getType() == Ty && Offset->getType() == Ty) {
+ auto *NewOp = BinaryOperator::CreateAdd(Base, Offset);
+ NewOp->setHasNoUnsignedWrap(true);
+ return NewOp;
+ }
+
return commonCastTransforms(CI);
}
diff --git a/llvm/test/Transforms/InstCombine/cast_ptr.ll b/llvm/test/Transforms/InstCombine/cast_ptr.ll
index 5c6c012064e0..0e191748226d 100644
--- a/llvm/test/Transforms/InstCombine/cast_ptr.ll
+++ b/llvm/test/Transforms/InstCombine/cast_ptr.ll
@@ -244,3 +244,57 @@ define <2 x i32> @insertelt_extra_use2(<2 x i32> %x, ptr %p) {
%r = ptrtoint <2 x ptr> %i to <2 x i32>
ret <2 x i32> %r
}
+
+define i32 @ptr_add_in_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @ptr_add_in_int(
+; CHECK-NEXT: [[R:%.*]] = add nuw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %ptr = inttoptr i32 %x to ptr
+ %p2 = getelementptr inbounds i8, ptr %ptr, i32 %y
+ %r = ptrtoint ptr %p2 to i32
+ ret i32 %r
+}
+
+define i32 @ptr_add_in_int_const(i32 %x) {
+; CHECK-LABEL: @ptr_add_in_int_const(
+; CHECK-NEXT: [[R:%.*]] = add nuw i32 [[X:%.*]], 4096
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %ptr = inttoptr i32 %x to ptr
+ %p2 = getelementptr inbounds i8, ptr %ptr, i32 4096
+ %r = ptrtoint ptr %p2 to i32
+ ret i32 %r
+}
+
+declare void @use_ptr(ptr)
+
+define i32 @ptr_add_in_int_extra_use1(i32 %x) {
+; CHECK-LABEL: @ptr_add_in_int_extra_use1(
+; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[X:%.*]] to ptr
+; CHECK-NEXT: call void @use_ptr(ptr [[PTR]])
+; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i32 4096
+; CHECK-NEXT: [[R:%.*]] = ptrtoint ptr [[P2]] to i32
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %ptr = inttoptr i32 %x to ptr
+ call void @use_ptr(ptr %ptr)
+ %p2 = getelementptr inbounds i8, ptr %ptr, i32 4096
+ %r = ptrtoint ptr %p2 to i32
+ ret i32 %r
+}
+
+define i32 @ptr_add_in_int_extra_use2(i32 %x) {
+; CHECK-LABEL: @ptr_add_in_int_extra_use2(
+; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[X:%.*]] to ptr
+; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i32 4096
+; CHECK-NEXT: call void @use_ptr(ptr nonnull [[P2]])
+; CHECK-NEXT: [[R:%.*]] = ptrtoint ptr [[P2]] to i32
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %ptr = inttoptr i32 %x to ptr
+ %p2 = getelementptr inbounds i8, ptr %ptr, i32 4096
+ call void @use_ptr(ptr %p2)
+ %r = ptrtoint ptr %p2 to i32
+ ret i32 %r
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a reasonable transform to me.
More generally, we could fold ptrtoint(gep p, x)
to add ptrtoint(p), x
, but I think this may currently interfere with some other things, so I'm fine with checking this specific pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
LGTM as well. |
Fold
where both
%base
and%ptr
have only one use, toThe
add
can benuw
if the GEP isinbounds
and the offset is non-negative. The relevant Alive2 proof is https://alive2.llvm.org/ce/z/nP3RWy.Motivation
It seems unnecessary to convert
int
toptr
just to get its offset. In most cases, they generates the same assembly, but sometimes it may miss some optimizations since the analysis ofGEP
is not as perfect as that of arithmetic operation. One example ishttps://github.com/dtcxzyw/llvm-opt-benchmark/blob/e3c822bf41df3a88ca38eba884a52b0cc7e70bf2/bench/protobuf/optimized/generated_message_reflection.cc.ll#L39860-L39873
where
%conv.i188
first adds%125
and then subtracts%125
(the result is%sub.ptr.sub
), which can be optimized.But this fold involves
ptr
, which Alive2 can't verify, plus that in most cases, they generate the same assembly, I am not sure whether it is profitable.