; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes='loop(loop-idiom)' < %s -S | FileCheck %s

declare void @other()
declare void @use(ptr)
declare void @usei(i32)
declare void @usel(i64)

; size_t basic_strlen(const char* str) {
;     while (*str != '\0') {
;         ++str;
;     }
;     return str - base;
; }
define i64 @valid_basic_strlen(ptr %str) {
; CHECK-LABEL: define i64 @valid_basic_strlen(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[STRLEN:%.*]] = call i64 @strlen(ptr [[STR]])
; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 [[STRLEN]]
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[SCEVGEP]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    ret i64 [[SUB_PTR_SUB]]
;
entry:
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]
  %0 = load i8, ptr %str.addr.0, align 1
  %cmp.not = icmp eq i8 %0, 0
  %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1
  br i1 %cmp.not, label %while.end, label %while.cond

while.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
  ret i64 %sub.ptr.sub
}

; int valid_basic_strlen_rotated(const char* str) {
;     const char* base = str;
;     if (!*str) return 0;
;     do {
;         ++str;
;     } while (*str);
;     return str - base;
; }
define i32 @valid_basic_strlen_rotated(ptr %str) {
; CHECK-LABEL: define i32 @valid_basic_strlen_rotated(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[CLEANUP:.*]], label %[[DO_BODY_PREHEADER:.*]]
; CHECK:       [[DO_BODY_PREHEADER]]:
; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 1
; CHECK-NEXT:    [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]])
; CHECK-NEXT:    [[TMP1:%.*]] = add i64 [[STRLEN]], 1
; CHECK-NEXT:    [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[STR]], i64 [[TMP1]]
; CHECK-NEXT:    br label %[[DO_BODY:.*]]
; CHECK:       [[DO_BODY]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[DO_BODY]] ], [ [[STR]], %[[DO_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1
; CHECK-NEXT:    [[TOBOOL1_NOT:%.*]] = icmp eq i8 [[TMP2]], 0
; CHECK-NEXT:    br i1 [[TOBOOL1_NOT]], label %[[DO_END:.*]], label %[[DO_BODY]]
; CHECK:       [[DO_END]]:
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[SCEVGEP1]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    [[CONV:%.*]] = trunc i64 [[SUB_PTR_SUB]] to i32
; CHECK-NEXT:    br label %[[CLEANUP]]
; CHECK:       [[CLEANUP]]:
; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], %[[DO_END]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT:    ret i32 [[RETVAL_0]]
;
entry:
  %0 = load i8, ptr %str, align 1
  %tobool.not = icmp eq i8 %0, 0
  br i1 %tobool.not, label %cleanup, label %do.body

do.body:
  %str.addr.0 = phi ptr [ %incdec.ptr, %do.body ], [ %str, %entry ]
  %incdec.ptr = getelementptr inbounds nuw i8, ptr %str.addr.0, i64 1
  %1 = load i8, ptr %incdec.ptr, align 1
  %tobool1.not = icmp eq i8 %1, 0
  br i1 %tobool1.not, label %do.end, label %do.body

do.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %incdec.ptr to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
  %conv = trunc i64 %sub.ptr.sub to i32
  br label %cleanup

cleanup:
  %retval.0 = phi i32 [ %conv, %do.end ], [ 0, %entry ]
  ret i32 %retval.0
}

; int valid_strlen_with_aux_indvar(const char* str) {
;   int count = 0;
;   int count_offset = -10;
;   int count_multiple = 0;
;
;   while (*str) {
;     ++str;
;     ++count;
;     ++count_offset;
;     count_multiple += 2;
;     ++foo;
;   }
;
;   usei(count);
;   usei(count_offset);
;   usei(count_multiple);
;   use(str);
;   use(foo);
; }
define dso_local void @valid_strlen_with_aux_indvar(ptr noundef %str, ptr noundef %foo) local_unnamed_addr {
; CHECK-LABEL: define dso_local void @valid_strlen_with_aux_indvar(
; CHECK-SAME: ptr noundef [[STR:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT9:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_NOT9]], label %[[WHILE_END:.*]], label %[[WHILE_BODY_PREHEADER:.*]]
; CHECK:       [[WHILE_BODY_PREHEADER]]:
; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 1
; CHECK-NEXT:    [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]])
; CHECK-NEXT:    [[TMP1:%.*]] = add i64 [[STRLEN]], 1
; CHECK-NEXT:    [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[STR]], i64 [[TMP1]]
; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[STRLEN]] to i32
; CHECK-NEXT:    [[TMP3:%.*]] = add i32 [[TMP2]], 1
; CHECK-NEXT:    [[TMP4:%.*]] = trunc i64 [[STRLEN]] to i32
; CHECK-NEXT:    [[TMP5:%.*]] = add i32 [[TMP4]], -9
; CHECK-NEXT:    [[TMP6:%.*]] = trunc i64 [[STRLEN]] to i32
; CHECK-NEXT:    [[TMP7:%.*]] = shl i32 [[TMP6]], 1
; CHECK-NEXT:    [[TMP8:%.*]] = add i32 [[TMP7]], 2
; CHECK-NEXT:    [[TMP9:%.*]] = add i64 [[STRLEN]], 1
; CHECK-NEXT:    [[SCEVGEP2:%.*]] = getelementptr i8, ptr [[FOO]], i64 [[TMP9]]
; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]
; CHECK:       [[WHILE_BODY]]:
; CHECK-NEXT:    [[COUNT_MULTIPLE_014:%.*]] = phi i32 [ [[ADD:%.*]], %[[WHILE_BODY]] ], [ 0, %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[COUNT_OFFSET_013:%.*]] = phi i32 [ [[INC1:%.*]], %[[WHILE_BODY]] ], [ -10, %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[COUNT_012:%.*]] = phi i32 [ [[INC:%.*]], %[[WHILE_BODY]] ], [ 0, %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[FOO_ADDR_011:%.*]] = phi ptr [ [[INCDEC_PTR2:%.*]], %[[WHILE_BODY]] ], [ [[FOO]], %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[STR_ADDR_010:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY]] ], [ [[STR]], %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[STR_ADDR_010]], i64 1
; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[COUNT_012]], 1
; CHECK-NEXT:    [[INC1]] = add nsw i32 [[COUNT_OFFSET_013]], 1
; CHECK-NEXT:    [[ADD]] = add nuw nsw i32 [[COUNT_MULTIPLE_014]], 2
; CHECK-NEXT:    [[INCDEC_PTR2]] = getelementptr inbounds nuw i8, ptr [[FOO_ADDR_011]], i64 1
; CHECK-NEXT:    [[TMP10:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP10]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY]]
; CHECK:       [[WHILE_END_LOOPEXIT]]:
; CHECK-NEXT:    br label %[[WHILE_END]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[SCEVGEP1]], %[[WHILE_END_LOOPEXIT]] ]
; CHECK-NEXT:    [[FOO_ADDR_0_LCSSA:%.*]] = phi ptr [ [[FOO]], %[[ENTRY]] ], [ [[SCEVGEP2]], %[[WHILE_END_LOOPEXIT]] ]
; CHECK-NEXT:    [[COUNT_0_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[TMP3]], %[[WHILE_END_LOOPEXIT]] ]
; CHECK-NEXT:    [[COUNT_OFFSET_0_LCSSA:%.*]] = phi i32 [ -10, %[[ENTRY]] ], [ [[TMP5]], %[[WHILE_END_LOOPEXIT]] ]
; CHECK-NEXT:    [[COUNT_MULTIPLE_0_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[TMP8]], %[[WHILE_END_LOOPEXIT]] ]
; CHECK-NEXT:    tail call void @usei(i32 noundef [[COUNT_0_LCSSA]])
; CHECK-NEXT:    tail call void @usei(i32 noundef [[COUNT_OFFSET_0_LCSSA]])
; CHECK-NEXT:    tail call void @usei(i32 noundef [[COUNT_MULTIPLE_0_LCSSA]])
; CHECK-NEXT:    tail call void @use(ptr noundef nonnull [[STR_ADDR_0_LCSSA]])
; CHECK-NEXT:    tail call void @use(ptr noundef [[FOO_ADDR_0_LCSSA]])
; CHECK-NEXT:    ret void
;
entry:
  %0 = load i8, ptr %str, align 1
  %tobool.not9 = icmp eq i8 %0, 0
  br i1 %tobool.not9, label %while.end, label %while.body

while.body:
  %count_multiple.014 = phi i32 [ %add, %while.body ], [ 0, %entry ]
  %count_offset.013 = phi i32 [ %inc1, %while.body ], [ -10, %entry ]
  %count.012 = phi i32 [ %inc, %while.body ], [ 0, %entry ]
  %foo.addr.011 = phi ptr [ %incdec.ptr2, %while.body ], [ %foo, %entry ]
  %str.addr.010 = phi ptr [ %incdec.ptr, %while.body ], [ %str, %entry ]
  %incdec.ptr = getelementptr inbounds nuw i8, ptr %str.addr.010, i64 1
  %inc = add nuw nsw i32 %count.012, 1
  %inc1 = add nsw i32 %count_offset.013, 1
  %add = add nuw nsw i32 %count_multiple.014, 2
  %incdec.ptr2 = getelementptr inbounds nuw i8, ptr %foo.addr.011, i64 1
  %1 = load i8, ptr %incdec.ptr, align 1
  %tobool.not = icmp eq i8 %1, 0
  br i1 %tobool.not, label %while.end, label %while.body

while.end:
  %str.addr.0.lcssa = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.body ]
  %foo.addr.0.lcssa = phi ptr [ %foo, %entry ], [ %incdec.ptr2, %while.body ]
  %count.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.body ]
  %count_offset.0.lcssa = phi i32 [ -10, %entry ], [ %inc1, %while.body ]
  %count_multiple.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.body ]
  tail call void @usei(i32 noundef %count.0.lcssa) #3
  tail call void @usei(i32 noundef %count_offset.0.lcssa) #3
  tail call void @usei(i32 noundef %count_multiple.0.lcssa) #3
  tail call void @use(ptr noundef nonnull %str.addr.0.lcssa) #3
  tail call void @use(ptr noundef %foo.addr.0.lcssa) #3
  ret void
}

; int valid_strlen_index(const char* str) {
;     int i = 0;
;     while (str[i]) {
;         ++i;
;     }
;     return i;
; }
define i32 @valid_strlen_index(ptr %str) {
; CHECK-LABEL: define i32 @valid_strlen_index(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[STRLEN:%.*]] = call i64 @strlen(ptr [[STR]])
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[WHILE_COND]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[STR]], i64 [[INDVARS_IV]]
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw nsw i64 [[STRLEN]] to i32
; CHECK-NEXT:    ret i32 [[TMP1]]
;
entry:
  br label %while.cond

while.cond:
  %indvars.iv = phi i64 [ %indvars.iv.next, %while.cond ], [ 0, %entry ]
  %arrayidx = getelementptr inbounds i8, ptr %str, i64 %indvars.iv
  %0 = load i8, ptr %arrayidx, align 1
  %tobool.not = icmp eq i8 %0, 0
  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
  br i1 %tobool.not, label %while.end, label %while.cond

while.end:
  %1 = trunc nuw nsw i64 %indvars.iv to i32
  ret i32 %1
}

; void valid_strlen_offset(const my_char* str) {
;     if (*(str++) == '\0') return;
;     if (*(str++) == '\0') return;
;     if (*(str++) == '\0') return;
;     while (*str) {
;         ++str;
;     }
;     use(str);
; }
define dso_local void @valid_strlen_offset(ptr noundef %str) local_unnamed_addr {
; CHECK-LABEL: define dso_local void @valid_strlen_offset(
; CHECK-SAME: ptr noundef [[STR:%.*]]) local_unnamed_addr {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR]], align 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[CMP]], label %[[RETURN:.*]], label %[[IF_END:.*]]
; CHECK:       [[IF_END]]:
; CHECK-NEXT:    [[INCDEC_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[STR]], i64 1
; CHECK-NEXT:    [[TMP1:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1
; CHECK-NEXT:    [[CMP4:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT:    br i1 [[CMP4]], label %[[RETURN]], label %[[IF_END7:.*]]
; CHECK:       [[IF_END7]]:
; CHECK-NEXT:    [[INCDEC_PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[STR]], i64 2
; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[INCDEC_PTR2]], align 1
; CHECK-NEXT:    [[CMP10:%.*]] = icmp eq i8 [[TMP2]], 0
; CHECK-NEXT:    br i1 [[CMP10]], label %[[RETURN]], label %[[WHILE_COND_PREHEADER:.*]]
; CHECK:       [[WHILE_COND_PREHEADER]]:
; CHECK-NEXT:    [[INCDEC_PTR8:%.*]] = getelementptr i8, ptr [[STR]], i64 3
; CHECK-NEXT:    [[STRLEN:%.*]] = call i64 @strlen(ptr [[INCDEC_PTR8]])
; CHECK-NEXT:    [[TMP3:%.*]] = add i64 [[STRLEN]], 3
; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 [[TMP3]]
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[INCDEC_PTR14:%.*]], %[[WHILE_COND]] ], [ [[INCDEC_PTR8]], %[[WHILE_COND_PREHEADER]] ]
; CHECK-NEXT:    [[TMP4:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP4]], 0
; CHECK-NEXT:    [[INCDEC_PTR14]] = getelementptr inbounds nuw i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    tail call void @use(ptr noundef nonnull [[SCEVGEP]])
; CHECK-NEXT:    br label %[[RETURN]]
; CHECK:       [[RETURN]]:
; CHECK-NEXT:    ret void
;
entry:
  %0 = load i8, ptr %str, align 1
  %cmp = icmp eq i8 %0, 0
  br i1 %cmp, label %return, label %if.end

if.end:
  %incdec.ptr = getelementptr inbounds nuw i8, ptr %str, i64 1
  %1 = load i8, ptr %incdec.ptr, align 1
  %cmp4 = icmp eq i8 %1, 0
  br i1 %cmp4, label %return, label %if.end7

if.end7:
  %incdec.ptr2 = getelementptr inbounds nuw i8, ptr %str, i64 2
  %2 = load i8, ptr %incdec.ptr2, align 1
  %cmp10 = icmp eq i8 %2, 0
  br i1 %cmp10, label %return, label %while.cond.preheader

while.cond.preheader:
  %incdec.ptr8 = getelementptr inbounds nuw i8, ptr %str, i64 3
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %incdec.ptr14, %while.cond ], [ %incdec.ptr8, %while.cond.preheader ]
  %3 = load i8, ptr %str.addr.0, align 1
  %tobool.not = icmp eq i8 %3, 0
  %incdec.ptr14 = getelementptr inbounds nuw i8, ptr %str.addr.0, i64 1
  br i1 %tobool.not, label %while.end, label %while.cond

while.end:
  tail call void @use(ptr noundef nonnull %str.addr.0) #3
  br label %return

return:
  ret void
}

; void valid_nested_idiom(const char** strs, int n) {
;     for (int i = 0; i < n; ++i) {
;         const char* s = strs[i];
;         int count = 0;
;         while (*s) {
;             ++s;
;             ++count;
;         }
;         usei(count);
;     }
; }
define void @valid_nested_idiom(ptr %strs, i32 %n) {
; CHECK-LABEL: define void @valid_nested_idiom(
; CHECK-SAME: ptr [[STRS:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[CMP9:%.*]] = icmp sgt i32 [[N]], 0
; CHECK-NEXT:    br i1 [[CMP9]], label %[[FOR_BODY_PREHEADER:.*]], label %[[FOR_COND_CLEANUP:.*]]
; CHECK:       [[FOR_BODY_PREHEADER]]:
; CHECK-NEXT:    [[WIDE_TRIP_COUNT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT:    br label %[[FOR_BODY:.*]]
; CHECK:       [[FOR_COND_CLEANUP_LOOPEXIT:.*]]:
; CHECK-NEXT:    br label %[[FOR_COND_CLEANUP]]
; CHECK:       [[FOR_COND_CLEANUP]]:
; CHECK-NEXT:    ret void
; CHECK:       [[FOR_BODY]]:
; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, %[[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[WHILE_END:.*]] ]
; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[STRS]], i64 [[INDVARS_IV]]
; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
; CHECK-NEXT:    [[TMP1:%.*]] = load i8, ptr [[TMP0]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT6:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_NOT6]], label %[[WHILE_END]], label %[[WHILE_BODY_PREHEADER:.*]]
; CHECK:       [[WHILE_BODY_PREHEADER]]:
; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 1
; CHECK-NEXT:    [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]])
; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[STRLEN]] to i32
; CHECK-NEXT:    [[TMP3:%.*]] = add i32 [[TMP2]], 1
; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]
; CHECK:       [[WHILE_BODY]]:
; CHECK-NEXT:    [[COUNT_08:%.*]] = phi i32 [ [[INC:%.*]], %[[WHILE_BODY]] ], [ 0, %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[S_07:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY]] ], [ [[TMP0]], %[[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[S_07]], i64 1
; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[COUNT_08]], 1
; CHECK-NEXT:    [[TMP4:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1
; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP4]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY]]
; CHECK:       [[WHILE_END_LOOPEXIT]]:
; CHECK-NEXT:    br label %[[WHILE_END]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[COUNT_0_LCSSA:%.*]] = phi i32 [ 0, %[[FOR_BODY]] ], [ [[TMP3]], %[[WHILE_END_LOOPEXIT]] ]
; CHECK-NEXT:    tail call void @usei(i32 [[COUNT_0_LCSSA]])
; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[WIDE_TRIP_COUNT]]
; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], label %[[FOR_BODY]]
;
entry:
  %cmp9 = icmp sgt i32 %n, 0
  br i1 %cmp9, label %for.body.preheader, label %for.cond.cleanup

for.body.preheader:
  %wide.trip.count = zext nneg i32 %n to i64
  br label %for.body

for.cond.cleanup:
  ret void

for.body:
  %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, %while.end ]
  %arrayidx = getelementptr inbounds ptr, ptr %strs, i64 %indvars.iv
  %0 = load ptr, ptr %arrayidx, align 8
  %1 = load i8, ptr %0, align 1
  %tobool.not6 = icmp eq i8 %1, 0
  br i1 %tobool.not6, label %while.end, label %while.body

while.body:
  %count.08 = phi i32 [ %inc, %while.body ], [ 0, %for.body ]
  %s.07 = phi ptr [ %incdec.ptr, %while.body ], [ %0, %for.body ]
  %incdec.ptr = getelementptr inbounds nuw i8, ptr %s.07, i64 1
  %inc = add nuw nsw i32 %count.08, 1
  %2 = load i8, ptr %incdec.ptr, align 1
  %tobool.not = icmp eq i8 %2, 0
  br i1 %tobool.not, label %while.end, label %while.body

while.end:
  %count.0.lcssa = phi i32 [ 0, %for.body ], [ %inc, %while.body ]
  tail call void @usei(i32 %count.0.lcssa) #2
  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
  %exitcond.not = icmp eq i64 %indvars.iv.next, %wide.trip.count
  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}

define i64 @invalid_strlen_has_side_effects(ptr %str) {
; CHECK-LABEL: define i64 @invalid_strlen_has_side_effects(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr [[STR_ADDR_0]], align 1
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    ret i64 [[SUB_PTR_SUB]]
;
entry:
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]
  %0 = load volatile i8, ptr %str.addr.0, align 1
  %cmp.not = icmp eq i8 %0, 0
  %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1
  br i1 %cmp.not, label %while.end, label %while.cond

while.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
  ret i64 %sub.ptr.sub
}


define i8 @invalid_exit_phi_scev(ptr %str) {
; CHECK-LABEL: define i8 @invalid_exit_phi_scev(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[DOTLCSSA:%.*]] = phi i8 [ [[TMP0]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    ret i8 [[DOTLCSSA]]
;
entry:
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]
  %0 = load i8, ptr %str.addr.0, align 1
  %cmp.not = icmp eq i8 %0, 0
  %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1
  br i1 %cmp.not, label %while.end, label %while.cond

while.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast

  ; %0.lcssa has invalid scev rec {%0} expected to be {%str,+,constant}
  ret i8 %0
}



define i64 @invalid_branch_cond(ptr %str) {
; CHECK-LABEL: define i64 @invalid_branch_cond(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 10
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    ret i64 [[SUB_PTR_SUB]]
;
entry:
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]
  %0 = load i8, ptr %str.addr.0, align 1

  ; We compare against '\n' instead of '\0'
  %cmp.not = icmp eq i8 %0, 10

  %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1
  br i1 %cmp.not, label %while.end, label %while.cond

while.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
  ret i64 %sub.ptr.sub
}

define i64 @invalid_unknown_step_size(ptr %str, i64 %step) {
; CHECK-LABEL: define i64 @invalid_unknown_step_size(
; CHECK-SAME: ptr [[STR:%.*]], i64 [[STEP:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 [[STEP]]
; CHECK-NEXT:    br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    ret i64 [[SUB_PTR_SUB]]
;
entry:
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]
  %0 = load i8, ptr %str.addr.0, align 1
  %cmp.not = icmp eq i8 %0, 0
  %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 %step
  br i1 %cmp.not, label %while.end, label %while.cond

while.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
  ret i64 %sub.ptr.sub
}

declare ptr @pure(ptr) #0;
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }

define i64 @invalid_add_rec(ptr %str) {
; CHECK-LABEL: define i64 @invalid_add_rec(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br label %[[WHILE_COND:.*]]
; CHECK:       [[WHILE_COND]]:
; CHECK-NEXT:    [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[INDIRECT:%.*]] = tail call ptr @pure(ptr [[STR_ADDR_0]])
; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[INDIRECT]], align 1
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1
; CHECK-NEXT:    br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]
; CHECK:       [[WHILE_END]]:
; CHECK-NEXT:    [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]
; CHECK-NEXT:    [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64
; CHECK-NEXT:    [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64
; CHECK-NEXT:    [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]
; CHECK-NEXT:    ret i64 [[SUB_PTR_SUB]]
;
entry:
  br label %while.cond

while.cond:
  %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]
  %indirect = tail call ptr @pure(ptr %str.addr.0)
  %0 = load i8, ptr %indirect, align 1
  %cmp.not = icmp eq i8 %0, 0
  %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1
  br i1 %cmp.not, label %while.end, label %while.cond

while.end:
  %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64
  %sub.ptr.rhs.cast = ptrtoint ptr %str to i64
  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
  ret i64 %sub.ptr.sub
}

