diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 9e333202fb2e7..0258f0a90ea76 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2652,9 +2652,18 @@ static Instruction *canonicalizeGEPOfConstGEPI8(GetElementPtrInst &GEP, APInt NewOffset = TypeSize * *C2 + *C1; if (NewOffset.isZero() || (Src->hasOneUse() && GEP.getOperand(1)->hasOneUse())) { + GEPNoWrapFlags Flags = GEPNoWrapFlags::none(); + if (GEP.hasNoUnsignedWrap() && + cast(Src)->hasNoUnsignedWrap() && + match(GEP.getOperand(1), m_NUWAddLike(m_Value(), m_Value()))) { + Flags |= GEPNoWrapFlags::noUnsignedWrap(); + if (GEP.isInBounds() && cast(Src)->isInBounds()) + Flags |= GEPNoWrapFlags::inBounds(); + } + Value *GEPConst = - IC.Builder.CreatePtrAdd(Base, IC.Builder.getInt(NewOffset)); - return GetElementPtrInst::Create(BaseType, GEPConst, VarIndex); + IC.Builder.CreatePtrAdd(Base, IC.Builder.getInt(NewOffset), "", Flags); + return GetElementPtrInst::Create(BaseType, GEPConst, VarIndex, Flags); } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll index a92e0c263d357..e2f22b8322d2b 100644 --- a/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll +++ b/llvm/test/Transforms/InstCombine/gepofconstgepi8.ll @@ -293,3 +293,183 @@ entry: %p2 = getelementptr , ptr %p1, i64 %index ret ptr %p2 } + +define ptr @test_all_nuw(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_nuw( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr nuw i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr nuw i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr nuw i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_partial_nuw1(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_partial_nuw1( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_partial_nuw2(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_partial_nuw2( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr nuw i8, ptr %base, i64 1 + %index = add i64 %a, 2 + %p2 = getelementptr nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_partial_nuw3(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_partial_nuw3( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr nuw i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_nuw_disjoint(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_nuw_disjoint( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr nuw i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr nuw i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr nuw i8, ptr %base, i64 1 + %index = or disjoint i64 %a, 2 + %p2 = getelementptr nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_inbounds_nuw(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_inbounds_nuw( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds nuw i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr inbounds nuw i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr inbounds nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_partial_inbounds1(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_partial_inbounds1( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr nuw i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr nuw i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr nuw i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr inbounds nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_partial_inbounds2(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_partial_inbounds2( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr nuw i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr nuw i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr inbounds nuw i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_inbounds_partial_nuw1(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_inbounds_partial_nuw1( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[BASE]], i64 7 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr inbounds i8, ptr %base, i64 -1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr inbounds nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_inbounds_partial_nuw2(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_inbounds_partial_nuw2( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr inbounds nuw i8, ptr %base, i64 1 + %index = add nuw i64 %a, 2 + %p2 = getelementptr inbounds i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_inbounds_partial_nuw3(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_inbounds_partial_nuw3( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr inbounds nuw i8, ptr %base, i64 1 + %index = add i64 %a, 2 + %p2 = getelementptr inbounds nuw i32, ptr %p1, i64 %index + ret ptr %p2 +} + +define ptr @test_all_nusw_nuw(ptr %base, i64 %a) { +; CHECK-LABEL: define ptr @test_all_nusw_nuw( +; CHECK-SAME: ptr [[BASE:%.*]], i64 [[A:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr nuw i8, ptr [[BASE]], i64 9 +; CHECK-NEXT: [[P2:%.*]] = getelementptr nuw i32, ptr [[TMP0]], i64 [[A]] +; CHECK-NEXT: ret ptr [[P2]] +; +entry: + %p1 = getelementptr nusw nuw i8, ptr %base, i64 1 + %index = add nsw nuw i64 %a, 2 + %p2 = getelementptr nusw nuw i32, ptr %p1, i64 %index + ret ptr %p2 +}