[InstCombine] Preserve flags for difference of gep chains (#143488)
When expanding the offset of a GEP chain via a series of adds, try to
preserve the nsw/nuw flags based on inbounds/nuw. This is a followup to
https://github.com/llvm/llvm-project/pull/142958.
Proof: https://alive2.llvm.org/ce/z/8HiFYY (note that preserving nsw in
the nusw case is not valid)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 4b69586..fc7dd30 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2146,12 +2146,14 @@
bool RewriteGEPs = !Base.LHSGEPs.empty() && !Base.RHSGEPs.empty();
Type *IdxTy = DL.getIndexType(Base.Ptr->getType());
- auto EmitOffsetFromBase = [&](ArrayRef<GEPOperator *> GEPs) -> Value * {
+ auto EmitOffsetFromBase = [&](ArrayRef<GEPOperator *> GEPs,
+ GEPNoWrapFlags NW) -> Value * {
Value *Sum = nullptr;
for (GEPOperator *GEP : reverse(GEPs)) {
Value *Offset = EmitGEPOffset(GEP, RewriteGEPs);
if (Sum)
- Sum = Builder.CreateAdd(Sum, Offset);
+ Sum = Builder.CreateAdd(Sum, Offset, "", NW.hasNoUnsignedWrap(),
+ NW.isInBounds());
else
Sum = Offset;
}
@@ -2160,8 +2162,8 @@
return Sum;
};
- Value *Result = EmitOffsetFromBase(Base.LHSGEPs);
- Value *Offset2 = EmitOffsetFromBase(Base.RHSGEPs);
+ Value *Result = EmitOffsetFromBase(Base.LHSGEPs, Base.LHSNW);
+ Value *Offset2 = EmitOffsetFromBase(Base.RHSGEPs, Base.RHSNW);
// If this is a single inbounds GEP and the original sub was nuw,
// then the final multiplication is also nuw.
diff --git a/llvm/test/Transforms/InstCombine/sub-gep.ll b/llvm/test/Transforms/InstCombine/sub-gep.ll
index c2122f2..9444fef 100644
--- a/llvm/test/Transforms/InstCombine/sub-gep.ll
+++ b/llvm/test/Transforms/InstCombine/sub-gep.ll
@@ -945,7 +945,7 @@
define i64 @multiple_geps_inbounds(ptr %base, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @multiple_geps_inbounds(
-; CHECK-NEXT: [[D:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]]
+; CHECK-NEXT: [[D:%.*]] = add nsw i64 [[IDX:%.*]], [[IDX2:%.*]]
; CHECK-NEXT: ret i64 [[D]]
;
%p2 = getelementptr inbounds i8, ptr %base, i64 %idx
@@ -971,7 +971,7 @@
define i64 @multiple_geps_nuw(ptr %base, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @multiple_geps_nuw(
-; CHECK-NEXT: [[D:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]]
+; CHECK-NEXT: [[D:%.*]] = add nuw i64 [[IDX:%.*]], [[IDX2:%.*]]
; CHECK-NEXT: ret i64 [[D]]
;
%p2 = getelementptr nuw i8, ptr %base, i64 %idx
@@ -985,7 +985,7 @@
define i64 @multiple_geps_inbounds_nuw(ptr %base, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @multiple_geps_inbounds_nuw(
-; CHECK-NEXT: [[D:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]]
+; CHECK-NEXT: [[D:%.*]] = add nuw nsw i64 [[IDX:%.*]], [[IDX2:%.*]]
; CHECK-NEXT: ret i64 [[D]]
;
%p2 = getelementptr inbounds nuw i8, ptr %base, i64 %idx