blob: eaafe6b162f28cf382ce6089a559a4dabf86d0e5 [file] [log] [blame]
; 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 true, 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 true, 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 true, 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 true, 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 true, 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 true, 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
}
define i64 @valid_basic_strlen_with_dbg(ptr %str) {
; Make sure that the call to strlen has debug info attached.
; CHECK-LABEL: define i64 @valid_basic_strlen_with_dbg(
; CHECK-SAME: ptr [[STR:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[STR]]), !dbg [[DBGLOC1:![0-9]+]]
; 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, !dbg [[DBGLOC2:![0-9]+]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0, !dbg [[DBGLOC2]]
; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1, !dbg [[DBGLOC2]]
; CHECK-NEXT: br i1 true, label %[[WHILE_END:.*]], label %[[WHILE_COND]], !dbg [[DBGLOC1]]
; CHECK: [[WHILE_END]]:
; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[SCEVGEP]] to i64, !dbg [[DBGLOC2]]
; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64, !dbg [[DBGLOC2]]
; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]], !dbg [[DBGLOC2]]
; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]], !dbg [[DBGLOC2]]
;
; CHECK: [[DBGLOC1]] = !DILocation(line: 3, column: 3
; CHECK: [[DBGLOC2]] = !DILocation(line: 5, column: 3
;
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, !dbg !8
%cmp.not = icmp eq i8 %0, 0, !dbg !8
%incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1, !dbg !8
br i1 %cmp.not, label %while.end, label %while.cond, !dbg !4
while.end:
%sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64, !dbg !8
%sub.ptr.rhs.cast = ptrtoint ptr %str to i64, !dbg !8
%sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast, !dbg !8
ret i64 %sub.ptr.sub, !dbg !8
}
!llvm.module.flags = !{!0}
!llvm.dbg.cu = !{!1}
!0 = !{i32 1, !"Debug Info Version", i32 3}
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 2.9 (trunk 127165:127174)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, retainedTypes: !3)
!2 = !DIFile(filename: "strlen.c", directory: "/tmp")
!3 = !{}
!4 = !DILocation(line: 3, column: 3, scope: !5)
!5 = distinct !DILexicalBlock(scope: !6, file: !2, line: 2, column: 21)
!6 = distinct !DISubprogram(name: "foo", scope: !2, file: !2, line: 2, type: !7, virtualIndex: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !1)
!7 = !DISubroutineType(types: !3)
!8 = !DILocation(line: 5, column: 3, scope: !5)