-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[InstCombine] Canonicalize gep T* X, V / sizeof(T)
to gep i8* X, V
#76458
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
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesThis patch canonicalize As this pattern has been handled by the backends, the motivation of this patch is to reduce the ref count of sdiv, which will enable more optimizations. Full diff: https://github.com/llvm/llvm-project/pull/76458.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 7f5a7b666903db..fed311cec24a2f 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2470,20 +2470,18 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedValue();
bool Matched = false;
- uint64_t C;
Value *V = nullptr;
if (TyAllocSize == 1) {
V = GEP.getOperand(1);
Matched = true;
- } else if (match(GEP.getOperand(1),
- m_AShr(m_Value(V), m_ConstantInt(C)))) {
- if (TyAllocSize == 1ULL << C)
- Matched = true;
- } else if (match(GEP.getOperand(1),
- m_SDiv(m_Value(V), m_ConstantInt(C)))) {
- if (TyAllocSize == C)
- Matched = true;
- }
+ } else if (has_single_bit(TyAllocSize) &&
+ match(GEP.getOperand(1),
+ m_Exact(m_AShr(m_Value(V), m_SpecificInt(countr_zero(
+ TyAllocSize))))))
+ Matched = true;
+ else if (match(GEP.getOperand(1),
+ m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize)))))
+ Matched = true;
// Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y), but
// only if both point to the same underlying object (otherwise provenance
@@ -2494,6 +2492,14 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
getUnderlyingObject(X) == getUnderlyingObject(Y))
return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
+
+ // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V)
+ if (Matched && TyAllocSize != 1) {
+ GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
+ Builder.getInt8Ty(), GEP.getPointerOperand(), V);
+ NewGEP->setIsInBounds(GEP.isInBounds());
+ return NewGEP;
+ }
}
}
// We do not handle pointer-vector geps here.
diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index bc7fdc9352df6c..7d67f2583aa24d 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -1453,4 +1453,88 @@ define ptr @const_gep_chain(ptr %p, i64 %a) {
ret ptr %p4
}
+define ptr @gep_sdiv(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv(
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %index = sdiv exact i64 %off, 7
+ %ptr = getelementptr %struct.C, ptr %p, i64 %index
+ ret ptr %ptr
+}
+
+define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) {
+; CHECK-LABEL: @gep_sdiv_vec(
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, <2 x ptr> [[P:%.*]], <2 x i64> [[OFF:%.*]]
+; CHECK-NEXT: ret <2 x ptr> [[PTR]]
+;
+ %index = sdiv exact <2 x i64> %off, <i64 7, i64 7>
+ %ptr = getelementptr %struct.C, <2 x ptr> %p, <2 x i64> %index
+ ret <2 x ptr> %ptr
+}
+
+define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv_inbounds(
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %index = sdiv exact i64 %off, 7
+ %ptr = getelementptr inbounds %struct.C, ptr %p, i64 %index
+ ret ptr %ptr
+}
+
+define ptr @gep_ashr(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_ashr(
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %index = ashr exact i64 %off, 2
+ %ptr = getelementptr i32, ptr %p, i64 %index
+ ret ptr %ptr
+}
+
+; Negative tests
+
+define ptr @gep_i8(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_i8(
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %ptr = getelementptr i8, ptr %p, i64 %off
+ ret ptr %ptr
+}
+
+define ptr @gep_sdiv_mismatched_size(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv_mismatched_size(
+; CHECK-NEXT: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 20
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %index = sdiv exact i64 %off, 20
+ %ptr = getelementptr %struct.C, ptr %p, i64 %index
+ ret ptr %ptr
+}
+
+define ptr @gep_sdiv_without_exact(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv_without_exact(
+; CHECK-NEXT: [[INDEX:%.*]] = sdiv i64 [[OFF:%.*]], 7
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %index = sdiv i64 %off, 7
+ %ptr = getelementptr %struct.C, ptr %p, i64 %index
+ ret ptr %ptr
+}
+
+define ptr @gep_ashr_without_exact(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_ashr_without_exact(
+; CHECK-NEXT: [[INDEX:%.*]] = ashr i64 [[OFF:%.*]], 2
+; CHECK-NEXT: [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT: ret ptr [[PTR]]
+;
+ %index = ashr i64 %off, 2
+ %ptr = getelementptr i32, ptr %p, i64 %index
+ ret ptr %ptr
+}
+
!0 = !{!"branch_weights", i32 2, i32 10}
|
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
Extend the transform added in llvm#76458 to also handle unsigned division. X exact/ Y * Y == X holds independently of whether the division is signed or unsigned. Proofs: https://alive2.llvm.org/ce/z/wFd5Ec
Extend the transform added in #76458 to also handle unsigned division. X exact/ Y * Y == X holds independently of whether the division is signed or unsigned. Proofs: https://alive2.llvm.org/ce/z/wFd5Ec
Extend the transform added in llvm#76458 to also handle unsigned division. X exact/ Y * Y == X holds independently of whether the division is signed or unsigned. Proofs: https://alive2.llvm.org/ce/z/wFd5Ec (cherry picked from commit 26d4afc)
This patch canonicalize
gep T* X, V / sizeof(T)
togep i8* X, V
.Alive2: https://alive2.llvm.org/ce/z/7XGjiB
As this pattern has been handled by the backends, the motivation of this patch is to reduce the ref count of sdiv, which will enable more optimizations.
Related patch: #68882, #76384 and #76439