-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[InstCombine] Split GEPs with multiple non-zero offsets #151333
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
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
c6ec7ea to
b3b0946
Compare
|
@zyw-bot csmith-fuzz |
Currently this fold only supports a single GEP. However, in ptradd representation, it may be split across multiple GEPs. In particular, PR llvm#151333 will split off constant offset GEPs. To support this, add a new helper decomposeLinearExpression(), which decomposes a pointer into a linear expression of the form BasePtr + Index * Scale + Offset. I plan to also extend this helper to look through mul/shl on the index and use it in more places that currently use collectOffset() to extract a single index * scale. This will make sure such optimizations are not affected by the ptradd migration.
…157447) Currently this fold only supports a single GEP. However, in ptradd representation, it may be split across multiple GEPs. In particular, PR #151333 will split off constant offset GEPs. To support this, add a new helper decomposeLinearExpression(), which decomposes a pointer into a linear expression of the form BasePtr + Index * Scale + Offset. I plan to also extend this helper to look through mul/shl on the index and use it in more places that currently use collectOffset() to extract a single index * scale. This will make sure such optimizations are not affected by the ptradd migration.
4670e35 to
39daeb2
Compare
Split GEPs that have more than one non-zero offset into two GEPs. This is in preparation for the ptradd migration, which can only represent such GEPs. This also enables CSE and LICM of the common base.
39daeb2 to
a61c046
Compare
|
@llvm/pr-subscribers-llvm-analysis Author: Nikita Popov (nikic) ChangesSplit GEPs that have more than one non-zero offset into two GEPs. This is in preparation for the ptradd migration, which can only represent such GEPs. This also enables CSE and LICM of the common base. Patch is 110.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151333.diff 23 Files Affected:
diff --git a/clang/test/CodeGen/union-tbaa1.c b/clang/test/CodeGen/union-tbaa1.c
index 9f2b0e9fb7b09..3f6ada5023f27 100644
--- a/clang/test/CodeGen/union-tbaa1.c
+++ b/clang/test/CodeGen/union-tbaa1.c
@@ -19,16 +19,16 @@ void bar(vect32 p[][2]);
// CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP1]], [[NUM]]
// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP0]]
// CHECK-NEXT: store i32 [[MUL]], ptr [[ARRAYIDX2]], align 8, !tbaa [[TBAA6:![0-9]+]]
-// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR]], i32 [[TMP0]], i32 1
+// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX]], i32 4
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[MUL6:%.*]] = mul i32 [[TMP2]], [[NUM]]
-// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP0]], i32 1
+// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX2]], i32 4
// CHECK-NEXT: store i32 [[MUL6]], ptr [[ARRAYIDX8]], align 4, !tbaa [[TBAA6]]
// CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[MUL]], 16
// CHECK-NEXT: store i32 [[TMP3]], ptr [[VEC]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[INDEX]], align 4, !tbaa [[TBAA2]]
-// CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP4]], i32 1
-// CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX14]], i32 2
+// CHECK-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP4]]
+// CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX13]], i32 6
// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr [[ARRAYIDX15]], align 2, !tbaa [[TBAA6]]
// CHECK-NEXT: [[CONV16:%.*]] = zext i16 [[TMP5]] to i32
// CHECK-NEXT: [[ARRAYIDX17:%.*]] = getelementptr inbounds nuw i8, ptr [[VEC]], i32 4
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index a74f292524b4d..c2f045a2ab02e 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2744,125 +2744,53 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
if (auto *I = combineConstantOffsets(GEP, *this))
return I;
- // For constant GEPs, use a more general offset-based folding approach.
- Type *PtrTy = Src->getType()->getScalarType();
- if (GEP.hasAllConstantIndices() &&
- (Src->hasOneUse() || Src->hasAllConstantIndices())) {
- // Split Src into a variable part and a constant suffix.
- gep_type_iterator GTI = gep_type_begin(*Src);
- Type *BaseType = GTI.getIndexedType();
- bool IsFirstType = true;
- unsigned NumVarIndices = 0;
- for (auto Pair : enumerate(Src->indices())) {
- if (!isa<ConstantInt>(Pair.value())) {
- BaseType = GTI.getIndexedType();
- IsFirstType = false;
- NumVarIndices = Pair.index() + 1;
- }
- ++GTI;
- }
-
- // Determine the offset for the constant suffix of Src.
- APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);
- if (NumVarIndices != Src->getNumIndices()) {
- // FIXME: getIndexedOffsetInType() does not handled scalable vectors.
- if (BaseType->isScalableTy())
- return nullptr;
-
- SmallVector<Value *> ConstantIndices;
- if (!IsFirstType)
- ConstantIndices.push_back(
- Constant::getNullValue(Type::getInt32Ty(GEP.getContext())));
- append_range(ConstantIndices, drop_begin(Src->indices(), NumVarIndices));
- Offset += DL.getIndexedOffsetInType(BaseType, ConstantIndices);
- }
-
- // Add the offset for GEP (which is fully constant).
- if (!GEP.accumulateConstantOffset(DL, Offset))
- return nullptr;
-
- // Convert the total offset back into indices.
- SmallVector<APInt> ConstIndices =
- DL.getGEPIndicesForOffset(BaseType, Offset);
- if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero()))
- return nullptr;
-
- GEPNoWrapFlags NW = getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP));
- SmallVector<Value *> Indices(
- drop_end(Src->indices(), Src->getNumIndices() - NumVarIndices));
- for (const APInt &Idx : drop_begin(ConstIndices, !IsFirstType)) {
- Indices.push_back(ConstantInt::get(GEP.getContext(), Idx));
- // Even if the total offset is inbounds, we may end up representing it
- // by first performing a larger negative offset, and then a smaller
- // positive one. The large negative offset might go out of bounds. Only
- // preserve inbounds if all signs are the same.
- if (Idx.isNonNegative() != ConstIndices[0].isNonNegative())
- NW = NW.withoutNoUnsignedSignedWrap();
- if (!Idx.isNonNegative())
- NW = NW.withoutNoUnsignedWrap();
- }
-
- return replaceInstUsesWith(
- GEP, Builder.CreateGEP(Src->getSourceElementType(), Src->getOperand(0),
- Indices, "", NW));
- }
-
if (Src->getResultElementType() != GEP.getSourceElementType())
return nullptr;
- SmallVector<Value*, 8> Indices;
-
// Find out whether the last index in the source GEP is a sequential idx.
bool EndsWithSequential = false;
for (gep_type_iterator I = gep_type_begin(*Src), E = gep_type_end(*Src);
I != E; ++I)
EndsWithSequential = I.isSequential();
+ if (!EndsWithSequential)
+ return nullptr;
- // Can we combine the two pointer arithmetics offsets?
- if (EndsWithSequential) {
- // Replace: gep (gep %P, long B), long A, ...
- // With: T = long A+B; gep %P, T, ...
- Value *SO1 = Src->getOperand(Src->getNumOperands()-1);
- Value *GO1 = GEP.getOperand(1);
-
- // If they aren't the same type, then the input hasn't been processed
- // by the loop above yet (which canonicalizes sequential index types to
- // intptr_t). Just avoid transforming this until the input has been
- // normalized.
- if (SO1->getType() != GO1->getType())
- return nullptr;
+ // Replace: gep (gep %P, long B), long A, ...
+ // With: T = long A+B; gep %P, T, ...
+ Value *SO1 = Src->getOperand(Src->getNumOperands() - 1);
+ Value *GO1 = GEP.getOperand(1);
- Value *Sum =
- simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
- // Only do the combine when we are sure the cost after the
- // merge is never more than that before the merge.
- if (Sum == nullptr)
- return nullptr;
+ // If they aren't the same type, then the input hasn't been processed
+ // by the loop above yet (which canonicalizes sequential index types to
+ // intptr_t). Just avoid transforming this until the input has been
+ // normalized.
+ if (SO1->getType() != GO1->getType())
+ return nullptr;
- Indices.append(Src->op_begin()+1, Src->op_end()-1);
- Indices.push_back(Sum);
- Indices.append(GEP.op_begin()+2, GEP.op_end());
- } else if (isa<Constant>(*GEP.idx_begin()) &&
- cast<Constant>(*GEP.idx_begin())->isNullValue() &&
- Src->getNumOperands() != 1) {
- // Otherwise we can do the fold if the first index of the GEP is a zero
- Indices.append(Src->op_begin()+1, Src->op_end());
- Indices.append(GEP.idx_begin()+1, GEP.idx_end());
- }
-
- // Don't create GEPs with more than one variable index.
- unsigned NumVarIndices =
- count_if(Indices, [](Value *Idx) { return !isa<Constant>(Idx); });
- if (NumVarIndices > 1)
+ Value *Sum =
+ simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
+ // Only do the combine when we are sure the cost after the
+ // merge is never more than that before the merge.
+ if (Sum == nullptr)
return nullptr;
- if (!Indices.empty())
- return replaceInstUsesWith(
- GEP, Builder.CreateGEP(
- Src->getSourceElementType(), Src->getOperand(0), Indices, "",
- getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
+ SmallVector<Value *, 8> Indices;
+ Indices.append(Src->op_begin() + 1, Src->op_end() - 1);
+ Indices.push_back(Sum);
+ Indices.append(GEP.op_begin() + 2, GEP.op_end());
- return nullptr;
+ // Don't create GEPs with more than one non-zero index.
+ unsigned NumNonZeroIndices = count_if(Indices, [](Value *Idx) {
+ auto *C = dyn_cast<Constant>(Idx);
+ return !C || !C->isNullValue();
+ });
+ if (NumNonZeroIndices > 1)
+ return nullptr;
+
+ return replaceInstUsesWith(
+ GEP, Builder.CreateGEP(
+ Src->getSourceElementType(), Src->getOperand(0), Indices, "",
+ getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
}
Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
@@ -3334,17 +3262,18 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
return replaceInstUsesWith(GEP, Res);
}
- bool SeenVarIndex = false;
+ bool SeenNonZeroIndex = false;
for (auto [IdxNum, Idx] : enumerate(Indices)) {
- if (isa<Constant>(Idx))
+ auto *C = dyn_cast<Constant>(Idx);
+ if (C && C->isNullValue())
continue;
- if (!SeenVarIndex) {
- SeenVarIndex = true;
+ if (!SeenNonZeroIndex) {
+ SeenNonZeroIndex = true;
continue;
}
- // GEP has multiple variable indices: Split it.
+ // GEP has multiple non-zero indices: Split it.
ArrayRef<Value *> FrontIndices = ArrayRef(Indices).take_front(IdxNum);
Value *FrontGEP =
Builder.CreateGEP(GEPEltType, PtrOp, FrontIndices,
diff --git a/llvm/test/Analysis/BasicAA/featuretest.ll b/llvm/test/Analysis/BasicAA/featuretest.ll
index fd5d2eff10f83..e4cb009f0c633 100644
--- a/llvm/test/Analysis/BasicAA/featuretest.ll
+++ b/llvm/test/Analysis/BasicAA/featuretest.ll
@@ -102,12 +102,14 @@ define i32 @gep_distance_test(ptr %A) {
; cannot alias, even if there is a variable offset between them...
define i32 @gep_distance_test2(ptr %A, i64 %distance) {
; NO_ASSUME-LABEL: @gep_distance_test2(
-; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
+; NO_ASSUME-NEXT: [[B_SPLIT:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]]
+; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr i8, ptr [[B_SPLIT]], i64 4
; NO_ASSUME-NEXT: store i32 7, ptr [[B]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @gep_distance_test2(
-; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
+; USE_ASSUME-NEXT: [[B_SPLIT:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]]
+; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr i8, ptr [[B_SPLIT]], i64 4
; USE_ASSUME-NEXT: store i32 7, ptr [[B]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A]], i64 4), "nonnull"(ptr [[A]]), "align"(ptr [[A]], i64 4) ]
; USE_ASSUME-NEXT: ret i32 0
diff --git a/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll b/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
index ba36005244589..7e46f1f3c8d45 100644
--- a/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
+++ b/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
@@ -15,7 +15,7 @@ define ptr @foo(ptr %x, i32 %n) {
define ptr @bar(i64 %n, ptr %p) {
; CHECK-LABEL: define ptr @bar(
; CHECK-SAME: i64 [[N:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT: [[G:%.*]] = getelementptr { {}, [0 x { [0 x i8] }] }, ptr [[P]], i64 0, i32 1, i64 0, i32 0, i64 [[N]]
+; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 [[N]]
; CHECK-NEXT: ret ptr [[G]]
;
%g = getelementptr {{}, [0 x {[0 x i8]}]}, ptr %p, i64 %n, i32 1, i64 %n, i32 0, i64 %n
diff --git a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
index acea9f8f555c9..ecebaa7d9ae5d 100644
--- a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
+++ b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
@@ -118,7 +118,8 @@ define ptr @structStruct(ptr %p) {
; result = (ptr) &((struct.B*) p)[i].member1 + 2
define ptr @appendIndex(ptr %p, i64 %i) {
; CHECK-LABEL: @appendIndex(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]], i32 1, i64 2
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 6
; CHECK-NEXT: ret ptr [[TMP1]]
;
%1 = getelementptr inbounds %struct.B, ptr %p, i64 %i, i32 1
@@ -173,7 +174,8 @@ define ptr @partialConstant3(ptr %p) {
; result = &((struct.C*) p + a).member2
define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing1(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 8
; CHECK-NEXT: ret ptr [[TMP1]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
@@ -185,8 +187,8 @@ define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
; address of another member.
define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing2(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 1
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 1
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 5
; CHECK-NEXT: ret ptr [[TMP2]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
@@ -198,8 +200,8 @@ define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
; range of the object currently pointed by the non-constant GEP.
define ptr @partialConstantMemberAliasing3(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing3(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 4
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 12
; CHECK-NEXT: ret ptr [[TMP2]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 2
diff --git a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
index 5fb82d2328dde..42a4619645994 100644
--- a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
+++ b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
@@ -147,8 +147,8 @@ define ptr @test_too_many_indices(ptr %base, i64 %a, i64 %b) {
; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P1:%.*]] = getelementptr i8, ptr [[BASE]], i64 [[B]]
-; CHECK-NEXT: [[INDEX:%.*]] = add i64 [[A]], 1
-; CHECK-NEXT: [[P2:%.*]] = getelementptr [8 x i32], ptr [[P1]], i64 1, i64 [[INDEX]]
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[P1]], i64 36
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]]
; CHECK-NEXT: ret ptr [[P2]]
;
entry:
diff --git a/llvm/test/Transforms/InstCombine/gepphigep.ll b/llvm/test/Transforms/InstCombine/gepphigep.ll
index cd1e38bbb2dee..6a6b7708bbfc9 100644
--- a/llvm/test/Transforms/InstCombine/gepphigep.ll
+++ b/llvm/test/Transforms/InstCombine/gepphigep.ll
@@ -21,7 +21,8 @@ define i32 @test1(ptr %dm, i1 %c, i64 %idx1, i64 %idx2) {
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
; CHECK-NEXT: [[TMP0:%.*]] = phi i64 [ [[IDX1]], [[BB1]] ], [ [[IDX2]], [[BB2]] ]
-; CHECK-NEXT: [[INST24:%.*]] = getelementptr inbounds [[STRUCT2]], ptr [[INST1]], i64 [[TMP0]], i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT2]], ptr [[INST1]], i64 [[TMP0]]
+; CHECK-NEXT: [[INST24:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 4
; CHECK-NEXT: [[INST25:%.*]] = load i32, ptr [[INST24]], align 4
; CHECK-NEXT: ret i32 [[INST25]]
;
@@ -76,11 +77,13 @@ define i32 @test3(ptr %dm, i1 %c, i64 %idx1, i64 %idx2, i64 %idx3) personality p
; CHECK-NEXT: bb:
; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
-; CHECK-NEXT: [[INST1:%.*]] = getelementptr inbounds [[STRUCT3:%.*]], ptr [[DM:%.*]], i64 [[IDX1:%.*]], i32 1
+; CHECK-NEXT: [[INST1_SPLIT:%.*]] = getelementptr inbounds [[STRUCT3:%.*]], ptr [[DM:%.*]], i64 [[IDX1:%.*]]
+; CHECK-NEXT: [[INST1:%.*]] = getelementptr inbounds nuw i8, ptr [[INST1_SPLIT]], i64 4
; CHECK-NEXT: store i32 0, ptr [[INST1]], align 4
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[INST12:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[IDX2:%.*]], i32 1, i32 0, i32 1
+; CHECK-NEXT: [[INST2_SPLIT:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[IDX2:%.*]]
+; CHECK-NEXT: [[INST12:%.*]] = getelementptr inbounds nuw i8, ptr [[INST2_SPLIT]], i64 8
; CHECK-NEXT: store i32 0, ptr [[INST12]], align 4
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
@@ -92,8 +95,9 @@ define i32 @test3(ptr %dm, i1 %c, i64 %idx1, i64 %idx2, i64 %idx3) personality p
; CHECK: bb5:
; CHECK-NEXT: [[INST27:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: catch ptr @_ZTIi
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[TMP0]], i32 1
-; CHECK-NEXT: [[INST35:%.*]] = getelementptr inbounds [[STRUCT4:%.*]], ptr [[TMP1]], i64 [[IDX3:%.*]], i32 1, i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[TMP0]]
+; CHECK-NEXT: [[INST34_SPLIT:%.*]] = getelementptr [[STRUCT4:%.*]], ptr [[TMP1]], i64 [[IDX3:%.*]]
+; CHECK-NEXT: [[INST35:%.*]] = getelementptr i8, ptr [[INST34_SPLIT]], i64 16
; CHECK-NEXT: [[INST25:%.*]] = load i32, ptr [[INST35]], align 4
; CHECK-NEXT: ret i32 [[INST25]]
;
diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index 2758bdeb09e80..92b76c5d1b46a 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -1947,7 +1947,8 @@ define ptr @gep_merge_nusw_add_zero(ptr %p, i64 %idx, i64 %idx2) {
define ptr @gep_merge_nuw_const(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_merge_nuw_const(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[GEP1]], i64 4
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep1 = getelementptr nuw [2 x i32], ptr %p, i64 %idx
@@ -1970,7 +1971,8 @@ define ptr @gep_merge_nuw_const_neg(ptr %p, i64 %idx, i64 %idx2) {
; does not overflow.
define ptr @gep_merge_nusw_const(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_merge_nusw_const(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nusw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw nuw i8, ptr [[GEP1]], i64 4
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep1 = getelementptr nusw [2 x i32], ptr %p, i64 %idx
diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll
index f7d788110b1bc..10fe07295eed6 100644
--- a/llvm/test/Transforms/InstCombine/load-cmp.ll
+++ b/llvm/test/Transforms/InstCombine/load-cmp.ll
@@ -462,7 +462,7 @@ define i1 @load_vs_array_type_mismatch_offset2(i32 %idx) {
define i1 @offset_larger_than_stride(i32 %idx) {
; CHECK-LABEL: @offset_larger_than_stride(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i16], ptr @g_i16_1, i32 1, i32 [[TMP1:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = ge...
[truncated]
|
|
@llvm/pr-subscribers-clang Author: Nikita Popov (nikic) ChangesSplit GEPs that have more than one non-zero offset into two GEPs. This is in preparation for the ptradd migration, which can only represent such GEPs. This also enables CSE and LICM of the common base. Patch is 110.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151333.diff 23 Files Affected:
diff --git a/clang/test/CodeGen/union-tbaa1.c b/clang/test/CodeGen/union-tbaa1.c
index 9f2b0e9fb7b09..3f6ada5023f27 100644
--- a/clang/test/CodeGen/union-tbaa1.c
+++ b/clang/test/CodeGen/union-tbaa1.c
@@ -19,16 +19,16 @@ void bar(vect32 p[][2]);
// CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP1]], [[NUM]]
// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP0]]
// CHECK-NEXT: store i32 [[MUL]], ptr [[ARRAYIDX2]], align 8, !tbaa [[TBAA6:![0-9]+]]
-// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR]], i32 [[TMP0]], i32 1
+// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX]], i32 4
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[MUL6:%.*]] = mul i32 [[TMP2]], [[NUM]]
-// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP0]], i32 1
+// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX2]], i32 4
// CHECK-NEXT: store i32 [[MUL6]], ptr [[ARRAYIDX8]], align 4, !tbaa [[TBAA6]]
// CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[MUL]], 16
// CHECK-NEXT: store i32 [[TMP3]], ptr [[VEC]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[INDEX]], align 4, !tbaa [[TBAA2]]
-// CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP4]], i32 1
-// CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX14]], i32 2
+// CHECK-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP4]]
+// CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX13]], i32 6
// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr [[ARRAYIDX15]], align 2, !tbaa [[TBAA6]]
// CHECK-NEXT: [[CONV16:%.*]] = zext i16 [[TMP5]] to i32
// CHECK-NEXT: [[ARRAYIDX17:%.*]] = getelementptr inbounds nuw i8, ptr [[VEC]], i32 4
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index a74f292524b4d..c2f045a2ab02e 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2744,125 +2744,53 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
if (auto *I = combineConstantOffsets(GEP, *this))
return I;
- // For constant GEPs, use a more general offset-based folding approach.
- Type *PtrTy = Src->getType()->getScalarType();
- if (GEP.hasAllConstantIndices() &&
- (Src->hasOneUse() || Src->hasAllConstantIndices())) {
- // Split Src into a variable part and a constant suffix.
- gep_type_iterator GTI = gep_type_begin(*Src);
- Type *BaseType = GTI.getIndexedType();
- bool IsFirstType = true;
- unsigned NumVarIndices = 0;
- for (auto Pair : enumerate(Src->indices())) {
- if (!isa<ConstantInt>(Pair.value())) {
- BaseType = GTI.getIndexedType();
- IsFirstType = false;
- NumVarIndices = Pair.index() + 1;
- }
- ++GTI;
- }
-
- // Determine the offset for the constant suffix of Src.
- APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);
- if (NumVarIndices != Src->getNumIndices()) {
- // FIXME: getIndexedOffsetInType() does not handled scalable vectors.
- if (BaseType->isScalableTy())
- return nullptr;
-
- SmallVector<Value *> ConstantIndices;
- if (!IsFirstType)
- ConstantIndices.push_back(
- Constant::getNullValue(Type::getInt32Ty(GEP.getContext())));
- append_range(ConstantIndices, drop_begin(Src->indices(), NumVarIndices));
- Offset += DL.getIndexedOffsetInType(BaseType, ConstantIndices);
- }
-
- // Add the offset for GEP (which is fully constant).
- if (!GEP.accumulateConstantOffset(DL, Offset))
- return nullptr;
-
- // Convert the total offset back into indices.
- SmallVector<APInt> ConstIndices =
- DL.getGEPIndicesForOffset(BaseType, Offset);
- if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero()))
- return nullptr;
-
- GEPNoWrapFlags NW = getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP));
- SmallVector<Value *> Indices(
- drop_end(Src->indices(), Src->getNumIndices() - NumVarIndices));
- for (const APInt &Idx : drop_begin(ConstIndices, !IsFirstType)) {
- Indices.push_back(ConstantInt::get(GEP.getContext(), Idx));
- // Even if the total offset is inbounds, we may end up representing it
- // by first performing a larger negative offset, and then a smaller
- // positive one. The large negative offset might go out of bounds. Only
- // preserve inbounds if all signs are the same.
- if (Idx.isNonNegative() != ConstIndices[0].isNonNegative())
- NW = NW.withoutNoUnsignedSignedWrap();
- if (!Idx.isNonNegative())
- NW = NW.withoutNoUnsignedWrap();
- }
-
- return replaceInstUsesWith(
- GEP, Builder.CreateGEP(Src->getSourceElementType(), Src->getOperand(0),
- Indices, "", NW));
- }
-
if (Src->getResultElementType() != GEP.getSourceElementType())
return nullptr;
- SmallVector<Value*, 8> Indices;
-
// Find out whether the last index in the source GEP is a sequential idx.
bool EndsWithSequential = false;
for (gep_type_iterator I = gep_type_begin(*Src), E = gep_type_end(*Src);
I != E; ++I)
EndsWithSequential = I.isSequential();
+ if (!EndsWithSequential)
+ return nullptr;
- // Can we combine the two pointer arithmetics offsets?
- if (EndsWithSequential) {
- // Replace: gep (gep %P, long B), long A, ...
- // With: T = long A+B; gep %P, T, ...
- Value *SO1 = Src->getOperand(Src->getNumOperands()-1);
- Value *GO1 = GEP.getOperand(1);
-
- // If they aren't the same type, then the input hasn't been processed
- // by the loop above yet (which canonicalizes sequential index types to
- // intptr_t). Just avoid transforming this until the input has been
- // normalized.
- if (SO1->getType() != GO1->getType())
- return nullptr;
+ // Replace: gep (gep %P, long B), long A, ...
+ // With: T = long A+B; gep %P, T, ...
+ Value *SO1 = Src->getOperand(Src->getNumOperands() - 1);
+ Value *GO1 = GEP.getOperand(1);
- Value *Sum =
- simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
- // Only do the combine when we are sure the cost after the
- // merge is never more than that before the merge.
- if (Sum == nullptr)
- return nullptr;
+ // If they aren't the same type, then the input hasn't been processed
+ // by the loop above yet (which canonicalizes sequential index types to
+ // intptr_t). Just avoid transforming this until the input has been
+ // normalized.
+ if (SO1->getType() != GO1->getType())
+ return nullptr;
- Indices.append(Src->op_begin()+1, Src->op_end()-1);
- Indices.push_back(Sum);
- Indices.append(GEP.op_begin()+2, GEP.op_end());
- } else if (isa<Constant>(*GEP.idx_begin()) &&
- cast<Constant>(*GEP.idx_begin())->isNullValue() &&
- Src->getNumOperands() != 1) {
- // Otherwise we can do the fold if the first index of the GEP is a zero
- Indices.append(Src->op_begin()+1, Src->op_end());
- Indices.append(GEP.idx_begin()+1, GEP.idx_end());
- }
-
- // Don't create GEPs with more than one variable index.
- unsigned NumVarIndices =
- count_if(Indices, [](Value *Idx) { return !isa<Constant>(Idx); });
- if (NumVarIndices > 1)
+ Value *Sum =
+ simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
+ // Only do the combine when we are sure the cost after the
+ // merge is never more than that before the merge.
+ if (Sum == nullptr)
return nullptr;
- if (!Indices.empty())
- return replaceInstUsesWith(
- GEP, Builder.CreateGEP(
- Src->getSourceElementType(), Src->getOperand(0), Indices, "",
- getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
+ SmallVector<Value *, 8> Indices;
+ Indices.append(Src->op_begin() + 1, Src->op_end() - 1);
+ Indices.push_back(Sum);
+ Indices.append(GEP.op_begin() + 2, GEP.op_end());
- return nullptr;
+ // Don't create GEPs with more than one non-zero index.
+ unsigned NumNonZeroIndices = count_if(Indices, [](Value *Idx) {
+ auto *C = dyn_cast<Constant>(Idx);
+ return !C || !C->isNullValue();
+ });
+ if (NumNonZeroIndices > 1)
+ return nullptr;
+
+ return replaceInstUsesWith(
+ GEP, Builder.CreateGEP(
+ Src->getSourceElementType(), Src->getOperand(0), Indices, "",
+ getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
}
Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
@@ -3334,17 +3262,18 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
return replaceInstUsesWith(GEP, Res);
}
- bool SeenVarIndex = false;
+ bool SeenNonZeroIndex = false;
for (auto [IdxNum, Idx] : enumerate(Indices)) {
- if (isa<Constant>(Idx))
+ auto *C = dyn_cast<Constant>(Idx);
+ if (C && C->isNullValue())
continue;
- if (!SeenVarIndex) {
- SeenVarIndex = true;
+ if (!SeenNonZeroIndex) {
+ SeenNonZeroIndex = true;
continue;
}
- // GEP has multiple variable indices: Split it.
+ // GEP has multiple non-zero indices: Split it.
ArrayRef<Value *> FrontIndices = ArrayRef(Indices).take_front(IdxNum);
Value *FrontGEP =
Builder.CreateGEP(GEPEltType, PtrOp, FrontIndices,
diff --git a/llvm/test/Analysis/BasicAA/featuretest.ll b/llvm/test/Analysis/BasicAA/featuretest.ll
index fd5d2eff10f83..e4cb009f0c633 100644
--- a/llvm/test/Analysis/BasicAA/featuretest.ll
+++ b/llvm/test/Analysis/BasicAA/featuretest.ll
@@ -102,12 +102,14 @@ define i32 @gep_distance_test(ptr %A) {
; cannot alias, even if there is a variable offset between them...
define i32 @gep_distance_test2(ptr %A, i64 %distance) {
; NO_ASSUME-LABEL: @gep_distance_test2(
-; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
+; NO_ASSUME-NEXT: [[B_SPLIT:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]]
+; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr i8, ptr [[B_SPLIT]], i64 4
; NO_ASSUME-NEXT: store i32 7, ptr [[B]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @gep_distance_test2(
-; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
+; USE_ASSUME-NEXT: [[B_SPLIT:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]]
+; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr i8, ptr [[B_SPLIT]], i64 4
; USE_ASSUME-NEXT: store i32 7, ptr [[B]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A]], i64 4), "nonnull"(ptr [[A]]), "align"(ptr [[A]], i64 4) ]
; USE_ASSUME-NEXT: ret i32 0
diff --git a/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll b/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
index ba36005244589..7e46f1f3c8d45 100644
--- a/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
+++ b/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
@@ -15,7 +15,7 @@ define ptr @foo(ptr %x, i32 %n) {
define ptr @bar(i64 %n, ptr %p) {
; CHECK-LABEL: define ptr @bar(
; CHECK-SAME: i64 [[N:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT: [[G:%.*]] = getelementptr { {}, [0 x { [0 x i8] }] }, ptr [[P]], i64 0, i32 1, i64 0, i32 0, i64 [[N]]
+; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 [[N]]
; CHECK-NEXT: ret ptr [[G]]
;
%g = getelementptr {{}, [0 x {[0 x i8]}]}, ptr %p, i64 %n, i32 1, i64 %n, i32 0, i64 %n
diff --git a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
index acea9f8f555c9..ecebaa7d9ae5d 100644
--- a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
+++ b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
@@ -118,7 +118,8 @@ define ptr @structStruct(ptr %p) {
; result = (ptr) &((struct.B*) p)[i].member1 + 2
define ptr @appendIndex(ptr %p, i64 %i) {
; CHECK-LABEL: @appendIndex(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]], i32 1, i64 2
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 6
; CHECK-NEXT: ret ptr [[TMP1]]
;
%1 = getelementptr inbounds %struct.B, ptr %p, i64 %i, i32 1
@@ -173,7 +174,8 @@ define ptr @partialConstant3(ptr %p) {
; result = &((struct.C*) p + a).member2
define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing1(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 8
; CHECK-NEXT: ret ptr [[TMP1]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
@@ -185,8 +187,8 @@ define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
; address of another member.
define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing2(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 1
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 1
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 5
; CHECK-NEXT: ret ptr [[TMP2]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
@@ -198,8 +200,8 @@ define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
; range of the object currently pointed by the non-constant GEP.
define ptr @partialConstantMemberAliasing3(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing3(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 4
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 12
; CHECK-NEXT: ret ptr [[TMP2]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 2
diff --git a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
index 5fb82d2328dde..42a4619645994 100644
--- a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
+++ b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
@@ -147,8 +147,8 @@ define ptr @test_too_many_indices(ptr %base, i64 %a, i64 %b) {
; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P1:%.*]] = getelementptr i8, ptr [[BASE]], i64 [[B]]
-; CHECK-NEXT: [[INDEX:%.*]] = add i64 [[A]], 1
-; CHECK-NEXT: [[P2:%.*]] = getelementptr [8 x i32], ptr [[P1]], i64 1, i64 [[INDEX]]
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[P1]], i64 36
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]]
; CHECK-NEXT: ret ptr [[P2]]
;
entry:
diff --git a/llvm/test/Transforms/InstCombine/gepphigep.ll b/llvm/test/Transforms/InstCombine/gepphigep.ll
index cd1e38bbb2dee..6a6b7708bbfc9 100644
--- a/llvm/test/Transforms/InstCombine/gepphigep.ll
+++ b/llvm/test/Transforms/InstCombine/gepphigep.ll
@@ -21,7 +21,8 @@ define i32 @test1(ptr %dm, i1 %c, i64 %idx1, i64 %idx2) {
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
; CHECK-NEXT: [[TMP0:%.*]] = phi i64 [ [[IDX1]], [[BB1]] ], [ [[IDX2]], [[BB2]] ]
-; CHECK-NEXT: [[INST24:%.*]] = getelementptr inbounds [[STRUCT2]], ptr [[INST1]], i64 [[TMP0]], i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT2]], ptr [[INST1]], i64 [[TMP0]]
+; CHECK-NEXT: [[INST24:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 4
; CHECK-NEXT: [[INST25:%.*]] = load i32, ptr [[INST24]], align 4
; CHECK-NEXT: ret i32 [[INST25]]
;
@@ -76,11 +77,13 @@ define i32 @test3(ptr %dm, i1 %c, i64 %idx1, i64 %idx2, i64 %idx3) personality p
; CHECK-NEXT: bb:
; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
-; CHECK-NEXT: [[INST1:%.*]] = getelementptr inbounds [[STRUCT3:%.*]], ptr [[DM:%.*]], i64 [[IDX1:%.*]], i32 1
+; CHECK-NEXT: [[INST1_SPLIT:%.*]] = getelementptr inbounds [[STRUCT3:%.*]], ptr [[DM:%.*]], i64 [[IDX1:%.*]]
+; CHECK-NEXT: [[INST1:%.*]] = getelementptr inbounds nuw i8, ptr [[INST1_SPLIT]], i64 4
; CHECK-NEXT: store i32 0, ptr [[INST1]], align 4
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[INST12:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[IDX2:%.*]], i32 1, i32 0, i32 1
+; CHECK-NEXT: [[INST2_SPLIT:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[IDX2:%.*]]
+; CHECK-NEXT: [[INST12:%.*]] = getelementptr inbounds nuw i8, ptr [[INST2_SPLIT]], i64 8
; CHECK-NEXT: store i32 0, ptr [[INST12]], align 4
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
@@ -92,8 +95,9 @@ define i32 @test3(ptr %dm, i1 %c, i64 %idx1, i64 %idx2, i64 %idx3) personality p
; CHECK: bb5:
; CHECK-NEXT: [[INST27:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: catch ptr @_ZTIi
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[TMP0]], i32 1
-; CHECK-NEXT: [[INST35:%.*]] = getelementptr inbounds [[STRUCT4:%.*]], ptr [[TMP1]], i64 [[IDX3:%.*]], i32 1, i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[TMP0]]
+; CHECK-NEXT: [[INST34_SPLIT:%.*]] = getelementptr [[STRUCT4:%.*]], ptr [[TMP1]], i64 [[IDX3:%.*]]
+; CHECK-NEXT: [[INST35:%.*]] = getelementptr i8, ptr [[INST34_SPLIT]], i64 16
; CHECK-NEXT: [[INST25:%.*]] = load i32, ptr [[INST35]], align 4
; CHECK-NEXT: ret i32 [[INST25]]
;
diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index 2758bdeb09e80..92b76c5d1b46a 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -1947,7 +1947,8 @@ define ptr @gep_merge_nusw_add_zero(ptr %p, i64 %idx, i64 %idx2) {
define ptr @gep_merge_nuw_const(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_merge_nuw_const(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[GEP1]], i64 4
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep1 = getelementptr nuw [2 x i32], ptr %p, i64 %idx
@@ -1970,7 +1971,8 @@ define ptr @gep_merge_nuw_const_neg(ptr %p, i64 %idx, i64 %idx2) {
; does not overflow.
define ptr @gep_merge_nusw_const(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_merge_nusw_const(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nusw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw nuw i8, ptr [[GEP1]], i64 4
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep1 = getelementptr nusw [2 x i32], ptr %p, i64 %idx
diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll
index f7d788110b1bc..10fe07295eed6 100644
--- a/llvm/test/Transforms/InstCombine/load-cmp.ll
+++ b/llvm/test/Transforms/InstCombine/load-cmp.ll
@@ -462,7 +462,7 @@ define i1 @load_vs_array_type_mismatch_offset2(i32 %idx) {
define i1 @offset_larger_than_stride(i32 %idx) {
; CHECK-LABEL: @offset_larger_than_stride(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i16], ptr @g_i16_1, i32 1, i32 [[TMP1:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = ge...
[truncated]
|
|
@llvm/pr-subscribers-llvm-transforms Author: Nikita Popov (nikic) ChangesSplit GEPs that have more than one non-zero offset into two GEPs. This is in preparation for the ptradd migration, which can only represent such GEPs. This also enables CSE and LICM of the common base. Patch is 110.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151333.diff 23 Files Affected:
diff --git a/clang/test/CodeGen/union-tbaa1.c b/clang/test/CodeGen/union-tbaa1.c
index 9f2b0e9fb7b09..3f6ada5023f27 100644
--- a/clang/test/CodeGen/union-tbaa1.c
+++ b/clang/test/CodeGen/union-tbaa1.c
@@ -19,16 +19,16 @@ void bar(vect32 p[][2]);
// CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP1]], [[NUM]]
// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP0]]
// CHECK-NEXT: store i32 [[MUL]], ptr [[ARRAYIDX2]], align 8, !tbaa [[TBAA6:![0-9]+]]
-// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR]], i32 [[TMP0]], i32 1
+// CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX]], i32 4
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[MUL6:%.*]] = mul i32 [[TMP2]], [[NUM]]
-// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP0]], i32 1
+// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX2]], i32 4
// CHECK-NEXT: store i32 [[MUL6]], ptr [[ARRAYIDX8]], align 4, !tbaa [[TBAA6]]
// CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[MUL]], 16
// CHECK-NEXT: store i32 [[TMP3]], ptr [[VEC]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[INDEX]], align 4, !tbaa [[TBAA2]]
-// CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP4]], i32 1
-// CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX14]], i32 2
+// CHECK-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds [2 x %union.vect32], ptr [[TMP]], i32 [[TMP4]]
+// CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX13]], i32 6
// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr [[ARRAYIDX15]], align 2, !tbaa [[TBAA6]]
// CHECK-NEXT: [[CONV16:%.*]] = zext i16 [[TMP5]] to i32
// CHECK-NEXT: [[ARRAYIDX17:%.*]] = getelementptr inbounds nuw i8, ptr [[VEC]], i32 4
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index a74f292524b4d..c2f045a2ab02e 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2744,125 +2744,53 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
if (auto *I = combineConstantOffsets(GEP, *this))
return I;
- // For constant GEPs, use a more general offset-based folding approach.
- Type *PtrTy = Src->getType()->getScalarType();
- if (GEP.hasAllConstantIndices() &&
- (Src->hasOneUse() || Src->hasAllConstantIndices())) {
- // Split Src into a variable part and a constant suffix.
- gep_type_iterator GTI = gep_type_begin(*Src);
- Type *BaseType = GTI.getIndexedType();
- bool IsFirstType = true;
- unsigned NumVarIndices = 0;
- for (auto Pair : enumerate(Src->indices())) {
- if (!isa<ConstantInt>(Pair.value())) {
- BaseType = GTI.getIndexedType();
- IsFirstType = false;
- NumVarIndices = Pair.index() + 1;
- }
- ++GTI;
- }
-
- // Determine the offset for the constant suffix of Src.
- APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);
- if (NumVarIndices != Src->getNumIndices()) {
- // FIXME: getIndexedOffsetInType() does not handled scalable vectors.
- if (BaseType->isScalableTy())
- return nullptr;
-
- SmallVector<Value *> ConstantIndices;
- if (!IsFirstType)
- ConstantIndices.push_back(
- Constant::getNullValue(Type::getInt32Ty(GEP.getContext())));
- append_range(ConstantIndices, drop_begin(Src->indices(), NumVarIndices));
- Offset += DL.getIndexedOffsetInType(BaseType, ConstantIndices);
- }
-
- // Add the offset for GEP (which is fully constant).
- if (!GEP.accumulateConstantOffset(DL, Offset))
- return nullptr;
-
- // Convert the total offset back into indices.
- SmallVector<APInt> ConstIndices =
- DL.getGEPIndicesForOffset(BaseType, Offset);
- if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero()))
- return nullptr;
-
- GEPNoWrapFlags NW = getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP));
- SmallVector<Value *> Indices(
- drop_end(Src->indices(), Src->getNumIndices() - NumVarIndices));
- for (const APInt &Idx : drop_begin(ConstIndices, !IsFirstType)) {
- Indices.push_back(ConstantInt::get(GEP.getContext(), Idx));
- // Even if the total offset is inbounds, we may end up representing it
- // by first performing a larger negative offset, and then a smaller
- // positive one. The large negative offset might go out of bounds. Only
- // preserve inbounds if all signs are the same.
- if (Idx.isNonNegative() != ConstIndices[0].isNonNegative())
- NW = NW.withoutNoUnsignedSignedWrap();
- if (!Idx.isNonNegative())
- NW = NW.withoutNoUnsignedWrap();
- }
-
- return replaceInstUsesWith(
- GEP, Builder.CreateGEP(Src->getSourceElementType(), Src->getOperand(0),
- Indices, "", NW));
- }
-
if (Src->getResultElementType() != GEP.getSourceElementType())
return nullptr;
- SmallVector<Value*, 8> Indices;
-
// Find out whether the last index in the source GEP is a sequential idx.
bool EndsWithSequential = false;
for (gep_type_iterator I = gep_type_begin(*Src), E = gep_type_end(*Src);
I != E; ++I)
EndsWithSequential = I.isSequential();
+ if (!EndsWithSequential)
+ return nullptr;
- // Can we combine the two pointer arithmetics offsets?
- if (EndsWithSequential) {
- // Replace: gep (gep %P, long B), long A, ...
- // With: T = long A+B; gep %P, T, ...
- Value *SO1 = Src->getOperand(Src->getNumOperands()-1);
- Value *GO1 = GEP.getOperand(1);
-
- // If they aren't the same type, then the input hasn't been processed
- // by the loop above yet (which canonicalizes sequential index types to
- // intptr_t). Just avoid transforming this until the input has been
- // normalized.
- if (SO1->getType() != GO1->getType())
- return nullptr;
+ // Replace: gep (gep %P, long B), long A, ...
+ // With: T = long A+B; gep %P, T, ...
+ Value *SO1 = Src->getOperand(Src->getNumOperands() - 1);
+ Value *GO1 = GEP.getOperand(1);
- Value *Sum =
- simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
- // Only do the combine when we are sure the cost after the
- // merge is never more than that before the merge.
- if (Sum == nullptr)
- return nullptr;
+ // If they aren't the same type, then the input hasn't been processed
+ // by the loop above yet (which canonicalizes sequential index types to
+ // intptr_t). Just avoid transforming this until the input has been
+ // normalized.
+ if (SO1->getType() != GO1->getType())
+ return nullptr;
- Indices.append(Src->op_begin()+1, Src->op_end()-1);
- Indices.push_back(Sum);
- Indices.append(GEP.op_begin()+2, GEP.op_end());
- } else if (isa<Constant>(*GEP.idx_begin()) &&
- cast<Constant>(*GEP.idx_begin())->isNullValue() &&
- Src->getNumOperands() != 1) {
- // Otherwise we can do the fold if the first index of the GEP is a zero
- Indices.append(Src->op_begin()+1, Src->op_end());
- Indices.append(GEP.idx_begin()+1, GEP.idx_end());
- }
-
- // Don't create GEPs with more than one variable index.
- unsigned NumVarIndices =
- count_if(Indices, [](Value *Idx) { return !isa<Constant>(Idx); });
- if (NumVarIndices > 1)
+ Value *Sum =
+ simplifyAddInst(GO1, SO1, false, false, SQ.getWithInstruction(&GEP));
+ // Only do the combine when we are sure the cost after the
+ // merge is never more than that before the merge.
+ if (Sum == nullptr)
return nullptr;
- if (!Indices.empty())
- return replaceInstUsesWith(
- GEP, Builder.CreateGEP(
- Src->getSourceElementType(), Src->getOperand(0), Indices, "",
- getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
+ SmallVector<Value *, 8> Indices;
+ Indices.append(Src->op_begin() + 1, Src->op_end() - 1);
+ Indices.push_back(Sum);
+ Indices.append(GEP.op_begin() + 2, GEP.op_end());
- return nullptr;
+ // Don't create GEPs with more than one non-zero index.
+ unsigned NumNonZeroIndices = count_if(Indices, [](Value *Idx) {
+ auto *C = dyn_cast<Constant>(Idx);
+ return !C || !C->isNullValue();
+ });
+ if (NumNonZeroIndices > 1)
+ return nullptr;
+
+ return replaceInstUsesWith(
+ GEP, Builder.CreateGEP(
+ Src->getSourceElementType(), Src->getOperand(0), Indices, "",
+ getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
}
Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
@@ -3334,17 +3262,18 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
return replaceInstUsesWith(GEP, Res);
}
- bool SeenVarIndex = false;
+ bool SeenNonZeroIndex = false;
for (auto [IdxNum, Idx] : enumerate(Indices)) {
- if (isa<Constant>(Idx))
+ auto *C = dyn_cast<Constant>(Idx);
+ if (C && C->isNullValue())
continue;
- if (!SeenVarIndex) {
- SeenVarIndex = true;
+ if (!SeenNonZeroIndex) {
+ SeenNonZeroIndex = true;
continue;
}
- // GEP has multiple variable indices: Split it.
+ // GEP has multiple non-zero indices: Split it.
ArrayRef<Value *> FrontIndices = ArrayRef(Indices).take_front(IdxNum);
Value *FrontGEP =
Builder.CreateGEP(GEPEltType, PtrOp, FrontIndices,
diff --git a/llvm/test/Analysis/BasicAA/featuretest.ll b/llvm/test/Analysis/BasicAA/featuretest.ll
index fd5d2eff10f83..e4cb009f0c633 100644
--- a/llvm/test/Analysis/BasicAA/featuretest.ll
+++ b/llvm/test/Analysis/BasicAA/featuretest.ll
@@ -102,12 +102,14 @@ define i32 @gep_distance_test(ptr %A) {
; cannot alias, even if there is a variable offset between them...
define i32 @gep_distance_test2(ptr %A, i64 %distance) {
; NO_ASSUME-LABEL: @gep_distance_test2(
-; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
+; NO_ASSUME-NEXT: [[B_SPLIT:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]]
+; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr i8, ptr [[B_SPLIT]], i64 4
; NO_ASSUME-NEXT: store i32 7, ptr [[B]], align 4
; NO_ASSUME-NEXT: ret i32 0
;
; USE_ASSUME-LABEL: @gep_distance_test2(
-; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
+; USE_ASSUME-NEXT: [[B_SPLIT:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 [[DISTANCE:%.*]]
+; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr i8, ptr [[B_SPLIT]], i64 4
; USE_ASSUME-NEXT: store i32 7, ptr [[B]], align 4
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A]], i64 4), "nonnull"(ptr [[A]]), "align"(ptr [[A]], i64 4) ]
; USE_ASSUME-NEXT: ret i32 0
diff --git a/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll b/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
index ba36005244589..7e46f1f3c8d45 100644
--- a/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
+++ b/llvm/test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll
@@ -15,7 +15,7 @@ define ptr @foo(ptr %x, i32 %n) {
define ptr @bar(i64 %n, ptr %p) {
; CHECK-LABEL: define ptr @bar(
; CHECK-SAME: i64 [[N:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT: [[G:%.*]] = getelementptr { {}, [0 x { [0 x i8] }] }, ptr [[P]], i64 0, i32 1, i64 0, i32 0, i64 [[N]]
+; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 [[N]]
; CHECK-NEXT: ret ptr [[G]]
;
%g = getelementptr {{}, [0 x {[0 x i8]}]}, ptr %p, i64 %n, i32 1, i64 %n, i32 0, i64 %n
diff --git a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
index acea9f8f555c9..ecebaa7d9ae5d 100644
--- a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
+++ b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
@@ -118,7 +118,8 @@ define ptr @structStruct(ptr %p) {
; result = (ptr) &((struct.B*) p)[i].member1 + 2
define ptr @appendIndex(ptr %p, i64 %i) {
; CHECK-LABEL: @appendIndex(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]], i32 1, i64 2
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 6
; CHECK-NEXT: ret ptr [[TMP1]]
;
%1 = getelementptr inbounds %struct.B, ptr %p, i64 %i, i32 1
@@ -173,7 +174,8 @@ define ptr @partialConstant3(ptr %p) {
; result = &((struct.C*) p + a).member2
define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing1(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 8
; CHECK-NEXT: ret ptr [[TMP1]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
@@ -185,8 +187,8 @@ define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
; address of another member.
define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing2(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 1
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 1
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 5
; CHECK-NEXT: ret ptr [[TMP2]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
@@ -198,8 +200,8 @@ define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
; range of the object currently pointed by the non-constant GEP.
define ptr @partialConstantMemberAliasing3(ptr %p, i64 %a) {
; CHECK-LABEL: @partialConstantMemberAliasing3(
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 4
+; CHECK-NEXT: [[DOTSPLIT:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTSPLIT]], i64 12
; CHECK-NEXT: ret ptr [[TMP2]]
;
%1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 2
diff --git a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
index 5fb82d2328dde..42a4619645994 100644
--- a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
+++ b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
@@ -147,8 +147,8 @@ define ptr @test_too_many_indices(ptr %base, i64 %a, i64 %b) {
; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P1:%.*]] = getelementptr i8, ptr [[BASE]], i64 [[B]]
-; CHECK-NEXT: [[INDEX:%.*]] = add i64 [[A]], 1
-; CHECK-NEXT: [[P2:%.*]] = getelementptr [8 x i32], ptr [[P1]], i64 1, i64 [[INDEX]]
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[P1]], i64 36
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]]
; CHECK-NEXT: ret ptr [[P2]]
;
entry:
diff --git a/llvm/test/Transforms/InstCombine/gepphigep.ll b/llvm/test/Transforms/InstCombine/gepphigep.ll
index cd1e38bbb2dee..6a6b7708bbfc9 100644
--- a/llvm/test/Transforms/InstCombine/gepphigep.ll
+++ b/llvm/test/Transforms/InstCombine/gepphigep.ll
@@ -21,7 +21,8 @@ define i32 @test1(ptr %dm, i1 %c, i64 %idx1, i64 %idx2) {
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
; CHECK-NEXT: [[TMP0:%.*]] = phi i64 [ [[IDX1]], [[BB1]] ], [ [[IDX2]], [[BB2]] ]
-; CHECK-NEXT: [[INST24:%.*]] = getelementptr inbounds [[STRUCT2]], ptr [[INST1]], i64 [[TMP0]], i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT2]], ptr [[INST1]], i64 [[TMP0]]
+; CHECK-NEXT: [[INST24:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 4
; CHECK-NEXT: [[INST25:%.*]] = load i32, ptr [[INST24]], align 4
; CHECK-NEXT: ret i32 [[INST25]]
;
@@ -76,11 +77,13 @@ define i32 @test3(ptr %dm, i1 %c, i64 %idx1, i64 %idx2, i64 %idx3) personality p
; CHECK-NEXT: bb:
; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
-; CHECK-NEXT: [[INST1:%.*]] = getelementptr inbounds [[STRUCT3:%.*]], ptr [[DM:%.*]], i64 [[IDX1:%.*]], i32 1
+; CHECK-NEXT: [[INST1_SPLIT:%.*]] = getelementptr inbounds [[STRUCT3:%.*]], ptr [[DM:%.*]], i64 [[IDX1:%.*]]
+; CHECK-NEXT: [[INST1:%.*]] = getelementptr inbounds nuw i8, ptr [[INST1_SPLIT]], i64 4
; CHECK-NEXT: store i32 0, ptr [[INST1]], align 4
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[INST12:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[IDX2:%.*]], i32 1, i32 0, i32 1
+; CHECK-NEXT: [[INST2_SPLIT:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[IDX2:%.*]]
+; CHECK-NEXT: [[INST12:%.*]] = getelementptr inbounds nuw i8, ptr [[INST2_SPLIT]], i64 8
; CHECK-NEXT: store i32 0, ptr [[INST12]], align 4
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
@@ -92,8 +95,9 @@ define i32 @test3(ptr %dm, i1 %c, i64 %idx1, i64 %idx2, i64 %idx3) personality p
; CHECK: bb5:
; CHECK-NEXT: [[INST27:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: catch ptr @_ZTIi
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[TMP0]], i32 1
-; CHECK-NEXT: [[INST35:%.*]] = getelementptr inbounds [[STRUCT4:%.*]], ptr [[TMP1]], i64 [[IDX3:%.*]], i32 1, i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT3]], ptr [[DM]], i64 [[TMP0]]
+; CHECK-NEXT: [[INST34_SPLIT:%.*]] = getelementptr [[STRUCT4:%.*]], ptr [[TMP1]], i64 [[IDX3:%.*]]
+; CHECK-NEXT: [[INST35:%.*]] = getelementptr i8, ptr [[INST34_SPLIT]], i64 16
; CHECK-NEXT: [[INST25:%.*]] = load i32, ptr [[INST35]], align 4
; CHECK-NEXT: ret i32 [[INST25]]
;
diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index 2758bdeb09e80..92b76c5d1b46a 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -1947,7 +1947,8 @@ define ptr @gep_merge_nusw_add_zero(ptr %p, i64 %idx, i64 %idx2) {
define ptr @gep_merge_nuw_const(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_merge_nuw_const(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[GEP1]], i64 4
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep1 = getelementptr nuw [2 x i32], ptr %p, i64 %idx
@@ -1970,7 +1971,8 @@ define ptr @gep_merge_nuw_const_neg(ptr %p, i64 %idx, i64 %idx2) {
; does not overflow.
define ptr @gep_merge_nusw_const(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_merge_nusw_const(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nusw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw nuw i8, ptr [[GEP1]], i64 4
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep1 = getelementptr nusw [2 x i32], ptr %p, i64 %idx
diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll
index f7d788110b1bc..10fe07295eed6 100644
--- a/llvm/test/Transforms/InstCombine/load-cmp.ll
+++ b/llvm/test/Transforms/InstCombine/load-cmp.ll
@@ -462,7 +462,7 @@ define i1 @load_vs_array_type_mismatch_offset2(i32 %idx) {
define i1 @offset_larger_than_stride(i32 %idx) {
; CHECK-LABEL: @offset_larger_than_stride(
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i16], ptr @g_i16_1, i32 1, i32 [[TMP1:%.*]]
+; CHECK-NEXT: [[GEP:%.*]] = ge...
[truncated]
|
dtcxzyw
left a comment
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.
LG
Split GEPs that have more than one non-zero offset into two GEPs. This is in preparation for the ptradd migration, which can only represent such GEPs.
This also enables CSE and LICM of the common base.