Skip to content

Commit 29555ad

Browse files
authored
[InstCombine] Improve inbounds preservation for ADD+GEP -> GEP+GEP (#135155)
Given that we have a "add nuw" and a "getelementptr inbounds nuw" like this: %idx = add nuw i64 %idx1, %idx2 %gep = getelementptr inbounds nuw i32, ptr %ptr, i64 %idx Then we can preserve the "inbounds nuw" flag when transforming that into two getelementptr instructions: %gep1 = getelementptr inbounds nuw i32, ptr %ptr, i64 %idx1 %gep = getelementptr inbounds nuw i32, ptr %ptr, i64 %idx2 Similarly for just having "nuw", and "nusw nuw" instead of "inbounds nuw" on the getelementptr. Proof: https://alive2.llvm.org/ce/z/QSweWW
1 parent bcd7f54 commit 29555ad

File tree

2 files changed

+57
-58
lines changed

2 files changed

+57
-58
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3086,13 +3086,47 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
30863086
if (GEPType->isVectorTy())
30873087
return nullptr;
30883088

3089+
if (!GEP.isInBounds()) {
3090+
unsigned IdxWidth =
3091+
DL.getIndexSizeInBits(PtrOp->getType()->getPointerAddressSpace());
3092+
APInt BasePtrOffset(IdxWidth, 0);
3093+
Value *UnderlyingPtrOp =
3094+
PtrOp->stripAndAccumulateInBoundsConstantOffsets(DL, BasePtrOffset);
3095+
bool CanBeNull, CanBeFreed;
3096+
uint64_t DerefBytes = UnderlyingPtrOp->getPointerDereferenceableBytes(
3097+
DL, CanBeNull, CanBeFreed);
3098+
if (!CanBeNull && !CanBeFreed && DerefBytes != 0) {
3099+
if (GEP.accumulateConstantOffset(DL, BasePtrOffset) &&
3100+
BasePtrOffset.isNonNegative()) {
3101+
APInt AllocSize(IdxWidth, DerefBytes);
3102+
if (BasePtrOffset.ule(AllocSize)) {
3103+
return GetElementPtrInst::CreateInBounds(
3104+
GEP.getSourceElementType(), PtrOp, Indices, GEP.getName());
3105+
}
3106+
}
3107+
}
3108+
}
3109+
3110+
// nusw + nneg -> nuw
3111+
if (GEP.hasNoUnsignedSignedWrap() && !GEP.hasNoUnsignedWrap() &&
3112+
all_of(GEP.indices(), [&](Value *Idx) {
3113+
return isKnownNonNegative(Idx, SQ.getWithInstruction(&GEP));
3114+
})) {
3115+
GEP.setNoWrapFlags(GEP.getNoWrapFlags() | GEPNoWrapFlags::noUnsignedWrap());
3116+
return &GEP;
3117+
}
3118+
3119+
// These rewrites are trying to preserve inbounds/nuw attributes. So we want
3120+
// to do this after having tried to derive "nuw" above.
30893121
if (GEP.getNumIndices() == 1) {
3090-
// We can only preserve inbounds if the original gep is inbounds, the add
3091-
// is nsw, and the add operands are non-negative.
3092-
auto CanPreserveInBounds = [&](bool AddIsNSW, Value *Idx1, Value *Idx2) {
3093-
SimplifyQuery Q = SQ.getWithInstruction(&GEP);
3094-
return GEP.isInBounds() && AddIsNSW && isKnownNonNegative(Idx1, Q) &&
3095-
isKnownNonNegative(Idx2, Q);
3122+
// Given (gep p, x+y) we want to determine the common nowrap flags for both
3123+
// geps if transforming into (gep (gep p, x), y).
3124+
auto GetPreservedNoWrapFlags = [&](bool AddIsNUW) {
3125+
// We can preserve both "inbounds nuw", "nusw nuw" and "nuw" if we know
3126+
// that x + y does not have unsigned wrap.
3127+
if (GEP.hasNoUnsignedWrap() && AddIsNUW)
3128+
return GEP.getNoWrapFlags();
3129+
return GEPNoWrapFlags::none();
30963130
};
30973131

30983132
// Try to replace ADD + GEP with GEP + GEP.
@@ -3104,15 +3138,14 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
31043138
// as:
31053139
// %newptr = getelementptr i32, ptr %ptr, i64 %idx1
31063140
// %newgep = getelementptr i32, ptr %newptr, i64 %idx2
3107-
bool IsInBounds = CanPreserveInBounds(
3108-
cast<OverflowingBinaryOperator>(GEP.getOperand(1))->hasNoSignedWrap(),
3109-
Idx1, Idx2);
3141+
bool NUW = match(GEP.getOperand(1), m_NUWAddLike(m_Value(), m_Value()));
3142+
GEPNoWrapFlags NWFlags = GetPreservedNoWrapFlags(NUW);
31103143
auto *NewPtr =
31113144
Builder.CreateGEP(GEP.getSourceElementType(), GEP.getPointerOperand(),
3112-
Idx1, "", IsInBounds);
3113-
return replaceInstUsesWith(
3114-
GEP, Builder.CreateGEP(GEP.getSourceElementType(), NewPtr, Idx2, "",
3115-
IsInBounds));
3145+
Idx1, "", NWFlags);
3146+
return replaceInstUsesWith(GEP,
3147+
Builder.CreateGEP(GEP.getSourceElementType(),
3148+
NewPtr, Idx2, "", NWFlags));
31163149
}
31173150
ConstantInt *C;
31183151
if (match(GEP.getOperand(1), m_OneUse(m_SExtLike(m_OneUse(m_NSWAdd(
@@ -3123,51 +3156,20 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
31233156
// as:
31243157
// %newptr = getelementptr i32, ptr %ptr, i32 %idx1
31253158
// %newgep = getelementptr i32, ptr %newptr, i32 idx2
3126-
bool IsInBounds = CanPreserveInBounds(
3127-
/*IsNSW=*/true, Idx1, C);
3159+
bool NUW = match(GEP.getOperand(1),
3160+
m_NNegZExt(m_NUWAddLike(m_Value(), m_Value())));
3161+
GEPNoWrapFlags NWFlags = GetPreservedNoWrapFlags(NUW);
31283162
auto *NewPtr = Builder.CreateGEP(
31293163
GEP.getSourceElementType(), GEP.getPointerOperand(),
3130-
Builder.CreateSExt(Idx1, GEP.getOperand(1)->getType()), "",
3131-
IsInBounds);
3164+
Builder.CreateSExt(Idx1, GEP.getOperand(1)->getType()), "", NWFlags);
31323165
return replaceInstUsesWith(
31333166
GEP,
31343167
Builder.CreateGEP(GEP.getSourceElementType(), NewPtr,
31353168
Builder.CreateSExt(C, GEP.getOperand(1)->getType()),
3136-
"", IsInBounds));
3169+
"", NWFlags));
31373170
}
31383171
}
31393172

3140-
if (!GEP.isInBounds()) {
3141-
unsigned IdxWidth =
3142-
DL.getIndexSizeInBits(PtrOp->getType()->getPointerAddressSpace());
3143-
APInt BasePtrOffset(IdxWidth, 0);
3144-
Value *UnderlyingPtrOp =
3145-
PtrOp->stripAndAccumulateInBoundsConstantOffsets(DL,
3146-
BasePtrOffset);
3147-
bool CanBeNull, CanBeFreed;
3148-
uint64_t DerefBytes = UnderlyingPtrOp->getPointerDereferenceableBytes(
3149-
DL, CanBeNull, CanBeFreed);
3150-
if (!CanBeNull && !CanBeFreed && DerefBytes != 0) {
3151-
if (GEP.accumulateConstantOffset(DL, BasePtrOffset) &&
3152-
BasePtrOffset.isNonNegative()) {
3153-
APInt AllocSize(IdxWidth, DerefBytes);
3154-
if (BasePtrOffset.ule(AllocSize)) {
3155-
return GetElementPtrInst::CreateInBounds(
3156-
GEP.getSourceElementType(), PtrOp, Indices, GEP.getName());
3157-
}
3158-
}
3159-
}
3160-
}
3161-
3162-
// nusw + nneg -> nuw
3163-
if (GEP.hasNoUnsignedSignedWrap() && !GEP.hasNoUnsignedWrap() &&
3164-
all_of(GEP.indices(), [&](Value *Idx) {
3165-
return isKnownNonNegative(Idx, SQ.getWithInstruction(&GEP));
3166-
})) {
3167-
GEP.setNoWrapFlags(GEP.getNoWrapFlags() | GEPNoWrapFlags::noUnsignedWrap());
3168-
return &GEP;
3169-
}
3170-
31713173
if (Instruction *R = foldSelectGEP(GEP, Builder))
31723174
return R;
31733175

llvm/test/Transforms/InstCombine/array.ll

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,38 +122,35 @@ define ptr @gep_inbounds_nuwaddlike(ptr %ptr, i64 %a, i64 %b) {
122122
ret ptr %gep
123123
}
124124

125-
; FIXME: Preserve "inbounds nuw".
126125
define ptr @gep_inbounds_add_nuw(ptr %ptr, i64 %a, i64 %b) {
127126
; CHECK-LABEL: define ptr @gep_inbounds_add_nuw(
128127
; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
129-
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
130-
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
128+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i32, ptr [[PTR]], i64 [[A]]
129+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds nuw i32, ptr [[TMP1]], i64 [[B]]
131130
; CHECK-NEXT: ret ptr [[GEP]]
132131
;
133132
%add = add nuw i64 %a, %b
134133
%gep = getelementptr inbounds nuw i32, ptr %ptr, i64 %add
135134
ret ptr %gep
136135
}
137136

138-
; FIXME: Preserve "nusw nuw".
139137
define ptr @gep_inbounds_add_nusw_nuw(ptr %ptr, i64 %a, i64 %b) {
140138
; CHECK-LABEL: define ptr @gep_inbounds_add_nusw_nuw(
141139
; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
142-
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
143-
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
140+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr nusw nuw i32, ptr [[PTR]], i64 [[A]]
141+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw nuw i32, ptr [[TMP1]], i64 [[B]]
144142
; CHECK-NEXT: ret ptr [[GEP]]
145143
;
146144
%add = add nuw i64 %a, %b
147145
%gep = getelementptr nusw nuw i32, ptr %ptr, i64 %add
148146
ret ptr %gep
149147
}
150148

151-
; FIXME: Preserve "nuw".
152149
define ptr @gep_add_nuw(ptr %ptr, i64 %a, i64 %b) {
153150
; CHECK-LABEL: define ptr @gep_add_nuw(
154151
; CHECK-SAME: ptr [[PTR:%.*]], i64 [[A:%.*]], i64 [[B:%.*]]) {
155-
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[PTR]], i64 [[A]]
156-
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[TMP1]], i64 [[B]]
152+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr nuw i32, ptr [[PTR]], i64 [[A]]
153+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i32, ptr [[TMP1]], i64 [[B]]
157154
; CHECK-NEXT: ret ptr [[GEP]]
158155
;
159156
%add = add nuw i64 %a, %b

0 commit comments

Comments
 (0)