[llvm] [InstCombine] Canonicalize `gep T* X, V / sizeof(T)` to `gep i8* X, V` (PR #76458)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 27 09:49:06 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Yingwei Zheng (dtcxzyw)
<details>
<summary>Changes</summary>
This patch canonicalize `gep T* X, V / sizeof(T)` to `gep 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
---
Full diff: https://github.com/llvm/llvm-project/pull/76458.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+16-10)
- (modified) llvm/test/Transforms/InstCombine/getelementptr.ll (+84)
``````````diff
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}
``````````
</details>
https://github.com/llvm/llvm-project/pull/76458
More information about the llvm-commits
mailing list