
Pass down the debug location to the generated strlen call because LLVM maintains that calls to inlinable functions must have debug info.
667 lines
29 KiB
LLVM
667 lines
29 KiB
LLVM
; 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)
|