[PATCH] D60935: [IndVarSimplify] Fixup nowrap flags during LFTR when moving to post-inc (PR31181)

Nikita Popov via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed May 29 14:16:18 PDT 2019


nikic marked an inline comment as done.
nikic added inline comments.


================
Comment at: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp:2383
+  // instruction, while SCEV has to explicitly prove the post-inc nowrap flags.
+  // TODO: This handling may be inaccurate for one case: If we switch to a
+  // dynamically dead IV that wraps on the first loop iteration only, which is
----------------
reames wrote:
> I don't think this is possible given hasConcreteDef.  It ensures the value on the first iteration is non-poison.  
hasConcreteDef() ensures that it's not poison on entry into the loop, but doesn't make sure that it's non-poison after the first iteration. The post-inc addrec only applies after the first iteration. Here is an example (CHECK lines are with this patch):

```
define i32 @switch_to_different_iv_first_poison(i32* %ptr, i1 %always_false) {
; CHECK-LABEL: @switch_to_different_iv_first_poison(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[FOR_COND:%.*]]
; CHECK:       for.cond:
; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN]] ]
; CHECK-NEXT:    store i32 [[IV]], i32* [[PTR:%.*]]
; CHECK-NEXT:    br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
; CHECK:       never_taken:
; CHECK-NEXT:    store volatile i32 [[IV2]], i32* [[PTR]]
; CHECK-NEXT:    br label [[ALWAYS_TAKEN]]
; CHECK:       always_taken:
; CHECK-NEXT:    [[IV2_INC]] = add nuw nsw i32 [[IV2]], 1
; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483628
; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
; CHECK:       for.end:
; CHECK-NEXT:    ret i32 0
;
entry:
  br label %for.cond

for.cond:
  %iv2 = phi i32 [ -1, %entry ], [ %iv2.inc, %always_taken ]
  %iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
  store i32 %iv, i32* %ptr
  br i1 %always_false, label %never_taken, label %always_taken

never_taken:
  store volatile i32 %iv2, i32* %ptr
  br label %always_taken

always_taken:
  %iv2.inc = add nuw nsw i32 %iv2, 1
  %iv.inc = add nsw i32 %iv, 1
  %cmp = icmp slt i32 %iv, 20
  br i1 %cmp, label %for.cond, label %for.end

for.end:
  ret i32 0
}
```

As you can see, we switched to `%iv2.inc`, but did not drop any nowrap flags.

Unfortunately I found out that there seems to be another issue that affects not just the first iteration. Here is a small variation on the above test case, starting from -2 instead of -1:

```
define i32 @switch_to_different_iv_second_poison(i32* %ptr, i1 %always_false) {
; CHECK-LABEL: @switch_to_different_iv_second_poison(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[FOR_COND:%.*]]
; CHECK:       for.cond:
; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ -2, [[ENTRY:%.*]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN]] ]
; CHECK-NEXT:    store i32 [[IV]], i32* [[PTR:%.*]]
; CHECK-NEXT:    br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
; CHECK:       never_taken:
; CHECK-NEXT:    store volatile i32 [[IV2]], i32* [[PTR]]
; CHECK-NEXT:    br label [[ALWAYS_TAKEN]]
; CHECK:       always_taken:
; CHECK-NEXT:    [[IV2_INC]] = add nsw i32 [[IV2]], 1
; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483629
; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
; CHECK:       for.end:
; CHECK-NEXT:    ret i32 0
;
entry:
  br label %for.cond

for.cond:
  %iv2 = phi i32 [ -2, %entry ], [ %iv2.inc, %always_taken ]
  %iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
  store i32 %iv, i32* %ptr
  br i1 %always_false, label %never_taken, label %always_taken

never_taken:
  store volatile i32 %iv2, i32* %ptr
  br label %always_taken

always_taken:
  %iv2.inc = add nuw nsw i32 %iv2, 1
  %iv.inc = add nsw i32 %iv, 1
  %cmp = icmp slt i32 %iv, 20
  br i1 %cmp, label %for.cond, label %for.end

for.end:
  ret i32 0
}
```

In this case the nuw flag is correctly dropped, but the nsw flag stays. I think this might be related to the fact that for the pre-inc addrec nowrap flags from IR are adopted unconditionally, and we may end up inferring something incorrect for the post-inc addrec from that (e.g. because it over-constrains ranges). I get the impression that SCEV might just not be prepared to deal with dynamically dead IVs.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60935/new/

https://reviews.llvm.org/D60935





More information about the llvm-commits mailing list