Skip to content

Commit 1c298c9

Browse files
committed
[InstCombine] Preserve nuw flags when merging geps
These transforms all perform a variant of (gep (gep p, x), y) to (gep p, (x + y)). We can preserve both inbounds and nuw during such transforms (https://alive2.llvm.org/ce/z/Stu4cN), but not nusw, which would require proving that the new add is nsw. For the constant offset case, I've conservatively retained the logic that checks for negative intermediate offsets, though I'm not sure it's still reachable nowadays.
1 parent a0f8890 commit 1c298c9

File tree

4 files changed

+137
-24
lines changed

4 files changed

+137
-24
lines changed

clang/test/CodeGen/attr-counted-by.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -686,15 +686,15 @@ size_t test6_bdos(struct anon_struct *p) {
686686
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
687687
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
688688
// SANITIZE-WITH-ATTR: cont7:
689-
// SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
689+
// SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 9
690690
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
691691
// SANITIZE-WITH-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8:![0-9]+]]
692692
// SANITIZE-WITH-ATTR-NEXT: ret void
693693
//
694694
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test7(
695695
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
696696
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
697-
// NO-SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
697+
// NO-SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 9
698698
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
699699
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
700700
// NO-SANITIZE-WITH-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6:![0-9]+]]
@@ -703,7 +703,7 @@ size_t test6_bdos(struct anon_struct *p) {
703703
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test7(
704704
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
705705
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
706-
// SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
706+
// SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 9
707707
// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
708708
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
709709
// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6:![0-9]+]]
@@ -712,7 +712,7 @@ size_t test6_bdos(struct anon_struct *p) {
712712
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test7(
713713
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
714714
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
715-
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
715+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 9
716716
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
717717
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
718718
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6:![0-9]+]]
@@ -778,7 +778,7 @@ size_t test7_bdos(struct union_of_fams *p) {
778778
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test8(
779779
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
780780
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
781-
// SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
781+
// SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 9
782782
// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
783783
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
784784
// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -787,7 +787,7 @@ size_t test7_bdos(struct union_of_fams *p) {
787787
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test8(
788788
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
789789
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
790-
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
790+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 9
791791
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
792792
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
793793
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -840,15 +840,15 @@ size_t test8_bdos(struct union_of_fams *p) {
840840
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB14:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
841841
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
842842
// SANITIZE-WITH-ATTR: cont7:
843-
// SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
843+
// SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
844844
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
845845
// SANITIZE-WITH-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]]
846846
// SANITIZE-WITH-ATTR-NEXT: ret void
847847
//
848848
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test9(
849849
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
850850
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
851-
// NO-SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
851+
// NO-SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
852852
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
853853
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
854854
// NO-SANITIZE-WITH-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -857,7 +857,7 @@ size_t test8_bdos(struct union_of_fams *p) {
857857
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test9(
858858
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
859859
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
860-
// SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
860+
// SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
861861
// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
862862
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
863863
// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -866,7 +866,7 @@ size_t test8_bdos(struct union_of_fams *p) {
866866
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test9(
867867
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
868868
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
869-
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
869+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
870870
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
871871
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
872872
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -936,7 +936,7 @@ size_t test9_bdos(struct union_of_fams *p) {
936936
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test10(
937937
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
938938
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
939-
// SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
939+
// SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
940940
// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
941941
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
942942
// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -945,7 +945,7 @@ size_t test9_bdos(struct union_of_fams *p) {
945945
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test10(
946946
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
947947
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
948-
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
948+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
949949
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
950950
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
951951
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -1583,15 +1583,15 @@ struct test26_foo {
15831583
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB30:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
15841584
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
15851585
// SANITIZE-WITH-ATTR: cont5:
1586-
// SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 8
1586+
// SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
15871587
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARR]], i64 0, i64 [[IDXPROM]]
15881588
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
15891589
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP2]]
15901590
//
15911591
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test26(
15921592
// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR2]] {
15931593
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
1594-
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 8
1594+
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
15951595
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[C]] to i64
15961596
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARR]], i64 0, i64 [[IDXPROM]]
15971597
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
@@ -1600,7 +1600,7 @@ struct test26_foo {
16001600
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test26(
16011601
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
16021602
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
1603-
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 8
1603+
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
16041604
// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[C]] to i64
16051605
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARR]], i64 0, i64 [[IDXPROM]]
16061606
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
@@ -1609,7 +1609,7 @@ struct test26_foo {
16091609
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test26(
16101610
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR6]] {
16111611
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
1612-
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 8
1612+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
16131613
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[C]] to i64
16141614
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARR]], i64 0, i64 [[IDXPROM]]
16151615
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]

clang/test/OpenMP/bug57757.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ void foo() {
4343
// CHECK-NEXT: br label [[DOTOMP_OUTLINED__EXIT]]
4444
// CHECK: .untied.next..i:
4545
// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 40
46-
// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 52
47-
// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 48
46+
// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 52
47+
// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 48
4848
// CHECK-NEXT: [[TMP8:%.*]] = load ptr, ptr [[TMP5]], align 8, !tbaa [[TBAA19:![0-9]+]], !noalias [[META13]]
4949
// CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP7]], align 4, !tbaa [[TBAA16]], !noalias [[META13]]
5050
// CHECK-NEXT: [[TMP10:%.*]] = load float, ptr [[TMP6]], align 4, !tbaa [[TBAA20:![0-9]+]], !noalias [[META13]]

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,8 +2327,16 @@ Instruction *InstCombinerImpl::narrowMathIfNoOverflow(BinaryOperator &BO) {
23272327
return CastInst::Create(CastOpc, NarrowBO, BO.getType());
23282328
}
23292329

2330-
static bool isMergedGEPInBounds(GEPOperator &GEP1, GEPOperator &GEP2) {
2331-
return GEP1.isInBounds() && GEP2.isInBounds();
2330+
/// Determine nowrap flags for (gep (gep p, x), y) to (gep p, (x + y))
2331+
/// transform.
2332+
static GEPNoWrapFlags getMergedGEPNoWrapFlags(GEPOperator &GEP1,
2333+
GEPOperator &GEP2) {
2334+
GEPNoWrapFlags NW = GEP1.getNoWrapFlags() & GEP2.getNoWrapFlags();
2335+
// Without inbounds, we could only preserve nusw if we know that x + y does
2336+
// not wrap.
2337+
if (!NW.isInBounds())
2338+
NW = NW.withoutNoUnsignedSignedWrap();
2339+
return NW;
23322340
}
23332341

23342342
/// Thread a GEP operation with constant indices through the constant true/false
@@ -2448,7 +2456,7 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
24482456
if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero()))
24492457
return nullptr;
24502458

2451-
bool IsInBounds = isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP));
2459+
GEPNoWrapFlags NW = getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP));
24522460
SmallVector<Value *> Indices;
24532461
append_range(Indices, drop_end(Src->indices(),
24542462
Src->getNumIndices() - NumVarIndices));
@@ -2458,12 +2466,15 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
24582466
// by first performing a larger negative offset, and then a smaller
24592467
// positive one. The large negative offset might go out of bounds. Only
24602468
// preserve inbounds if all signs are the same.
2461-
IsInBounds &= Idx.isNonNegative() == ConstIndices[0].isNonNegative();
2469+
if (Idx.isNonNegative() != ConstIndices[0].isNonNegative())
2470+
NW = NW.withoutNoUnsignedSignedWrap();
2471+
if (!Idx.isNonNegative())
2472+
NW = NW.withoutNoUnsignedWrap();
24622473
}
24632474

24642475
return replaceInstUsesWith(
24652476
GEP, Builder.CreateGEP(Src->getSourceElementType(), Src->getOperand(0),
2466-
Indices, "", IsInBounds));
2477+
Indices, "", NW));
24672478
}
24682479

24692480
if (Src->getResultElementType() != GEP.getSourceElementType())
@@ -2513,7 +2524,7 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
25132524
return replaceInstUsesWith(
25142525
GEP, Builder.CreateGEP(
25152526
Src->getSourceElementType(), Src->getOperand(0), Indices, "",
2516-
isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP))));
2527+
getMergedGEPNoWrapFlags(*Src, *cast<GEPOperator>(&GEP))));
25172528

25182529
return nullptr;
25192530
}

llvm/test/Transforms/InstCombine/getelementptr.ll

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,5 +1917,107 @@ define ptr @gep_merge_not_nuw(ptr %p, i64 %idx) {
19171917
ret ptr %gep
19181918
}
19191919

1920+
define ptr @gep_merge_nuw(ptr %p, i64 %x, i64 %y) {
1921+
; CHECK-LABEL: @gep_merge_nuw(
1922+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P:%.*]], i64 [[Y:%.*]]
1923+
; CHECK-NEXT: ret ptr [[GEP]]
1924+
;
1925+
%sub = sub i64 %y, %x
1926+
%gep1 = getelementptr nuw i8, ptr %p, i64 %x
1927+
%gep = getelementptr nuw i8, ptr %gep1, i64 %sub
1928+
ret ptr %gep
1929+
}
1930+
1931+
define ptr @gep_merge_nuw_only_one1(ptr %p, i64 %x, i64 %y) {
1932+
; CHECK-LABEL: @gep_merge_nuw_only_one1(
1933+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[Y:%.*]]
1934+
; CHECK-NEXT: ret ptr [[GEP]]
1935+
;
1936+
%sub = sub i64 %y, %x
1937+
%gep1 = getelementptr i8, ptr %p, i64 %x
1938+
%gep = getelementptr nuw i8, ptr %gep1, i64 %sub
1939+
ret ptr %gep
1940+
}
1941+
1942+
define ptr @gep_merge_nuw_only_one2(ptr %p, i64 %x, i64 %y) {
1943+
; CHECK-LABEL: @gep_merge_nuw_only_one2(
1944+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[Y:%.*]]
1945+
; CHECK-NEXT: ret ptr [[GEP]]
1946+
;
1947+
%sub = sub i64 %y, %x
1948+
%gep1 = getelementptr nuw i8, ptr %p, i64 %x
1949+
%gep = getelementptr i8, ptr %gep1, i64 %sub
1950+
ret ptr %gep
1951+
}
1952+
1953+
; Cannot preserve nusw, unless we know that the addition x + (y-x)
1954+
; does not overflow.
1955+
define ptr @gep_merge_nusw(ptr %p, i64 %x, i64 %y) {
1956+
; CHECK-LABEL: @gep_merge_nusw(
1957+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[Y:%.*]]
1958+
; CHECK-NEXT: ret ptr [[GEP]]
1959+
;
1960+
%sub = sub i64 %y, %x
1961+
%gep1 = getelementptr nusw i8, ptr %p, i64 %x
1962+
%gep = getelementptr nusw i8, ptr %gep1, i64 %sub
1963+
ret ptr %gep
1964+
}
1965+
1966+
define ptr @gep_merge_nuw_add_zero(ptr %p, i64 %idx, i64 %idx2) {
1967+
; CHECK-LABEL: @gep_merge_nuw_add_zero(
1968+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 [[IDX2:%.*]]
1969+
; CHECK-NEXT: ret ptr [[GEP]]
1970+
;
1971+
%gep1 = getelementptr nuw [2 x i32], ptr %p, i64 %idx
1972+
%gep = getelementptr nuw [2 x i32], ptr %gep1, i64 0, i64 %idx2
1973+
ret ptr %gep
1974+
}
1975+
1976+
; Cannot preserve nusw, even if the merge only involves an add with a zero
1977+
; index. This is because the whole offset calculation is required to be nsw
1978+
; after the merge.
1979+
define ptr @gep_merge_nusw_add_zero(ptr %p, i64 %idx, i64 %idx2) {
1980+
; CHECK-LABEL: @gep_merge_nusw_add_zero(
1981+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 [[IDX2:%.*]]
1982+
; CHECK-NEXT: ret ptr [[GEP]]
1983+
;
1984+
%gep1 = getelementptr nusw [2 x i32], ptr %p, i64 %idx
1985+
%gep = getelementptr nusw [2 x i32], ptr %gep1, i64 0, i64 %idx2
1986+
ret ptr %gep
1987+
}
1988+
1989+
define ptr @gep_merge_nuw_const(ptr %p, i64 %idx, i64 %idx2) {
1990+
; CHECK-LABEL: @gep_merge_nuw_const(
1991+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
1992+
; CHECK-NEXT: ret ptr [[GEP]]
1993+
;
1994+
%gep1 = getelementptr nuw [2 x i32], ptr %p, i64 %idx
1995+
%gep = getelementptr nuw i8, ptr %gep1, i64 4
1996+
ret ptr %gep
1997+
}
1998+
1999+
define ptr @gep_merge_nuw_const_neg(ptr %p, i64 %idx, i64 %idx2) {
2000+
; CHECK-LABEL: @gep_merge_nuw_const_neg(
2001+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
2002+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[GEP1]], i64 -4
2003+
; CHECK-NEXT: ret ptr [[GEP]]
2004+
;
2005+
%gep1 = getelementptr nuw [2 x i32], ptr %p, i64 %idx
2006+
%gep = getelementptr nuw i8, ptr %gep1, i64 -4
2007+
ret ptr %gep
2008+
}
2009+
2010+
; Cannot preserve nusw, because we don't know that the new offset calculation
2011+
; does not overflow.
2012+
define ptr @gep_merge_nusw_const(ptr %p, i64 %idx, i64 %idx2) {
2013+
; CHECK-LABEL: @gep_merge_nusw_const(
2014+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]], i64 1
2015+
; CHECK-NEXT: ret ptr [[GEP]]
2016+
;
2017+
%gep1 = getelementptr nusw [2 x i32], ptr %p, i64 %idx
2018+
%gep = getelementptr nusw i8, ptr %gep1, i64 4
2019+
ret ptr %gep
2020+
}
2021+
19202022

19212023
!0 = !{!"branch_weights", i32 2, i32 10}

0 commit comments

Comments
 (0)