[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