Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions clang/test/CodeGen/union-tbaa1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
149 changes: 39 additions & 110 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions llvm/test/Analysis/BasicAA/featuretest.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 8 additions & 6 deletions llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/InstCombine/gepofconstgepi8.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
14 changes: 9 additions & 5 deletions llvm/test/Transforms/InstCombine/gepphigep.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
;
Expand Down Expand Up @@ -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:
Expand All @@ -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]]
;
Expand Down
6 changes: 4 additions & 2 deletions llvm/test/Transforms/InstCombine/getelementptr.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions llvm/test/Transforms/InstCombine/load-cmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:%.*]] = getelementptr i16, ptr getelementptr inbounds nuw (i8, ptr @g_i16_1, i32 4), i32 [[IDX:%.*]]
; CHECK-NEXT: [[LOAD:%.*]] = load i16, ptr [[GEP]], align 2
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[LOAD]], 0
; CHECK-NEXT: ret i1 [[CMP]]
Expand Down Expand Up @@ -554,7 +554,7 @@ entry:
define i1 @cmp_load_constant_additional_positive_offset(i32 %x) {
; CHECK-LABEL: @cmp_load_constant_additional_positive_offset(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ISOK_PTR:%.*]] = getelementptr inbounds [1 x i32], ptr @CG_CLEAR, i32 5, i32 [[X:%.*]]
; CHECK-NEXT: [[ISOK_PTR:%.*]] = getelementptr inbounds i32, ptr getelementptr inbounds nuw (i8, ptr @CG_CLEAR, i32 20), i32 [[X:%.*]]
; CHECK-NEXT: [[ISOK:%.*]] = load i32, ptr [[ISOK_PTR]], align 4
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[ISOK]], 5
; CHECK-NEXT: ret i1 [[COND]]
Expand All @@ -569,7 +569,8 @@ entry:
define i1 @cmp_load_constant_additional_negative_offset(i32 %x) {
; CHECK-LABEL: @cmp_load_constant_additional_negative_offset(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ISOK_PTR:%.*]] = getelementptr inbounds [1 x i32], ptr @CG_CLEAR, i32 [[X:%.*]], i32 -5
; CHECK-NEXT: [[ISOK_PTR_SPLIT:%.*]] = getelementptr inbounds [1 x i32], ptr @CG_CLEAR, i32 [[X:%.*]]
; CHECK-NEXT: [[ISOK_PTR:%.*]] = getelementptr inbounds i8, ptr [[ISOK_PTR_SPLIT]], i32 -20
; CHECK-NEXT: [[ISOK:%.*]] = load i32, ptr [[ISOK_PTR]], align 4
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[ISOK]], 5
; CHECK-NEXT: ret i1 [[COND]]
Expand Down
Loading