diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 58b2d8e9dec1c..0858116cd9110 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2948,6 +2948,14 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { return nullptr; if (GEP.getNumIndices() == 1) { + // We can only preserve inbounds if the original gep is inbounds, the add + // is nsw, and the add operands are non-negative. + auto CanPreserveInBounds = [&](bool AddIsNSW, Value *Idx1, Value *Idx2) { + SimplifyQuery Q = SQ.getWithInstruction(&GEP); + return GEP.isInBounds() && AddIsNSW && isKnownNonNegative(Idx1, Q) && + isKnownNonNegative(Idx2, Q); + }; + // Try to replace ADD + GEP with GEP + GEP. Value *Idx1, *Idx2; if (match(GEP.getOperand(1), @@ -2957,10 +2965,15 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { // as: // %newptr = getelementptr i32, ptr %ptr, i64 %idx1 // %newgep = getelementptr i32, ptr %newptr, i64 %idx2 - auto *NewPtr = Builder.CreateGEP(GEP.getResultElementType(), - GEP.getPointerOperand(), Idx1); - return GetElementPtrInst::Create(GEP.getResultElementType(), NewPtr, - Idx2); + bool IsInBounds = CanPreserveInBounds( + cast(GEP.getOperand(1))->hasNoSignedWrap(), + Idx1, Idx2); + auto *NewPtr = + Builder.CreateGEP(GEP.getResultElementType(), GEP.getPointerOperand(), + Idx1, "", IsInBounds); + return replaceInstUsesWith( + GEP, Builder.CreateGEP(GEP.getResultElementType(), NewPtr, Idx2, "", + IsInBounds)); } ConstantInt *C; if (match(GEP.getOperand(1), m_OneUse(m_SExtLike(m_OneUse(m_NSWAdd( @@ -2971,12 +2984,17 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { // as: // %newptr = getelementptr i32, ptr %ptr, i32 %idx1 // %newgep = getelementptr i32, ptr %newptr, i32 idx2 + bool IsInBounds = CanPreserveInBounds( + /*IsNSW=*/true, Idx1, C); auto *NewPtr = Builder.CreateGEP( GEP.getResultElementType(), GEP.getPointerOperand(), - Builder.CreateSExt(Idx1, GEP.getOperand(1)->getType())); - return GetElementPtrInst::Create( - GEP.getResultElementType(), NewPtr, - Builder.CreateSExt(C, GEP.getOperand(1)->getType())); + Builder.CreateSExt(Idx1, GEP.getOperand(1)->getType()), "", + IsInBounds); + return replaceInstUsesWith( + GEP, + Builder.CreateGEP(GEP.getResultElementType(), NewPtr, + Builder.CreateSExt(C, GEP.getOperand(1)->getType()), + "", IsInBounds)); } } diff --git a/llvm/test/Transforms/InstCombine/array.ll b/llvm/test/Transforms/InstCombine/array.ll index f439d4da6080c..4f4ae17bebc50 100644 --- a/llvm/test/Transforms/InstCombine/array.ll +++ b/llvm/test/Transforms/InstCombine/array.ll @@ -116,8 +116,8 @@ define ptr @gep_inbounds_add_nsw_nonneg(ptr %ptr, i64 %a, i64 %b) { ; CHECK-NEXT: call void @llvm.assume(i1 [[A_NNEG]]) ; CHECK-NEXT: [[B_NNEG:%.*]] = icmp sgt i64 [[B]], -1 ; CHECK-NEXT: call void @llvm.assume(i1 [[B_NNEG]]) -; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]] -; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[A]] +; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[B]] ; CHECK-NEXT: ret ptr [[GEP]] ; %a.nneg = icmp sgt i64 %a, -1 @@ -207,8 +207,8 @@ define ptr @gep_inbounds_sext_add_nonneg(ptr %ptr, i32 %a) { ; CHECK-NEXT: [[A_NNEG:%.*]] = icmp sgt i32 [[A]], -1 ; CHECK-NEXT: call void @llvm.assume(i1 [[A_NNEG]]) ; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[A]] to i64 -; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[TMP1]] -; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 40 +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[TMP1]] +; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 40 ; CHECK-NEXT: ret ptr [[GEP]] ; %a.nneg = icmp sgt i32 %a, -1