667 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 52; RUN: opt -passes='loop(loop-idiom)' < %s -S | FileCheck %s3 4declare void @other()5declare void @use(ptr)6declare void @usei(i32)7declare void @usel(i64)8 9; size_t basic_strlen(const char* str) {10; while (*str != '\0') {11; ++str;12; }13; return str - base;14; }15define i64 @valid_basic_strlen(ptr %str) {16; CHECK-LABEL: define i64 @valid_basic_strlen(17; CHECK-SAME: ptr [[STR:%.*]]) {18; CHECK-NEXT: [[ENTRY:.*]]:19; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[STR]])20; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 [[STRLEN]]21; CHECK-NEXT: br label %[[WHILE_COND:.*]]22; CHECK: [[WHILE_COND]]:23; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]24; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 125; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 026; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 127; CHECK-NEXT: br i1 true, label %[[WHILE_END:.*]], label %[[WHILE_COND]]28; CHECK: [[WHILE_END]]:29; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[SCEVGEP]] to i6430; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i6431; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]32; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]]33;34entry:35 br label %while.cond36 37while.cond:38 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]39 %0 = load i8, ptr %str.addr.0, align 140 %cmp.not = icmp eq i8 %0, 041 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 142 br i1 %cmp.not, label %while.end, label %while.cond43 44while.end:45 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i6446 %sub.ptr.rhs.cast = ptrtoint ptr %str to i6447 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast48 ret i64 %sub.ptr.sub49}50 51; int valid_basic_strlen_rotated(const char* str) {52; const char* base = str;53; if (!*str) return 0;54; do {55; ++str;56; } while (*str);57; return str - base;58; }59define i32 @valid_basic_strlen_rotated(ptr %str) {60; CHECK-LABEL: define i32 @valid_basic_strlen_rotated(61; CHECK-SAME: ptr [[STR:%.*]]) {62; CHECK-NEXT: [[ENTRY:.*]]:63; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR]], align 164; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP0]], 065; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label %[[CLEANUP:.*]], label %[[DO_BODY_PREHEADER:.*]]66; CHECK: [[DO_BODY_PREHEADER]]:67; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 168; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]])69; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[STRLEN]], 170; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[STR]], i64 [[TMP1]]71; CHECK-NEXT: br label %[[DO_BODY:.*]]72; CHECK: [[DO_BODY]]:73; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[DO_BODY]] ], [ [[STR]], %[[DO_BODY_PREHEADER]] ]74; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[STR_ADDR_0]], i64 175; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[INCDEC_PTR]], align 176; CHECK-NEXT: [[TOBOOL1_NOT:%.*]] = icmp eq i8 [[TMP2]], 077; CHECK-NEXT: br i1 true, label %[[DO_END:.*]], label %[[DO_BODY]]78; CHECK: [[DO_END]]:79; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[SCEVGEP1]] to i6480; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i6481; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]82; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[SUB_PTR_SUB]] to i3283; CHECK-NEXT: br label %[[CLEANUP]]84; CHECK: [[CLEANUP]]:85; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CONV]], %[[DO_END]] ], [ 0, %[[ENTRY]] ]86; CHECK-NEXT: ret i32 [[RETVAL_0]]87;88entry:89 %0 = load i8, ptr %str, align 190 %tobool.not = icmp eq i8 %0, 091 br i1 %tobool.not, label %cleanup, label %do.body92 93do.body:94 %str.addr.0 = phi ptr [ %incdec.ptr, %do.body ], [ %str, %entry ]95 %incdec.ptr = getelementptr inbounds nuw i8, ptr %str.addr.0, i64 196 %1 = load i8, ptr %incdec.ptr, align 197 %tobool1.not = icmp eq i8 %1, 098 br i1 %tobool1.not, label %do.end, label %do.body99 100do.end:101 %sub.ptr.lhs.cast = ptrtoint ptr %incdec.ptr to i64102 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64103 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast104 %conv = trunc i64 %sub.ptr.sub to i32105 br label %cleanup106 107cleanup:108 %retval.0 = phi i32 [ %conv, %do.end ], [ 0, %entry ]109 ret i32 %retval.0110}111 112; int valid_strlen_with_aux_indvar(const char* str) {113; int count = 0;114; int count_offset = -10;115; int count_multiple = 0;116;117; while (*str) {118; ++str;119; ++count;120; ++count_offset;121; count_multiple += 2;122; ++foo;123; }124;125; usei(count);126; usei(count_offset);127; usei(count_multiple);128; use(str);129; use(foo);130; }131define dso_local void @valid_strlen_with_aux_indvar(ptr noundef %str, ptr noundef %foo) local_unnamed_addr {132; CHECK-LABEL: define dso_local void @valid_strlen_with_aux_indvar(133; CHECK-SAME: ptr noundef [[STR:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr {134; CHECK-NEXT: [[ENTRY:.*]]:135; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR]], align 1136; CHECK-NEXT: [[TOBOOL_NOT9:%.*]] = icmp eq i8 [[TMP0]], 0137; CHECK-NEXT: br i1 [[TOBOOL_NOT9]], label %[[WHILE_END:.*]], label %[[WHILE_BODY_PREHEADER:.*]]138; CHECK: [[WHILE_BODY_PREHEADER]]:139; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 1140; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]])141; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[STRLEN]], 1142; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[STR]], i64 [[TMP1]]143; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[STRLEN]] to i32144; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], 1145; CHECK-NEXT: [[TMP4:%.*]] = trunc i64 [[STRLEN]] to i32146; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], -9147; CHECK-NEXT: [[TMP6:%.*]] = trunc i64 [[STRLEN]] to i32148; CHECK-NEXT: [[TMP7:%.*]] = shl i32 [[TMP6]], 1149; CHECK-NEXT: [[TMP8:%.*]] = add i32 [[TMP7]], 2150; CHECK-NEXT: [[TMP9:%.*]] = add i64 [[STRLEN]], 1151; CHECK-NEXT: [[SCEVGEP2:%.*]] = getelementptr i8, ptr [[FOO]], i64 [[TMP9]]152; CHECK-NEXT: br label %[[WHILE_BODY:.*]]153; CHECK: [[WHILE_BODY]]:154; CHECK-NEXT: [[COUNT_MULTIPLE_014:%.*]] = phi i32 [ [[ADD:%.*]], %[[WHILE_BODY]] ], [ 0, %[[WHILE_BODY_PREHEADER]] ]155; CHECK-NEXT: [[COUNT_OFFSET_013:%.*]] = phi i32 [ [[INC1:%.*]], %[[WHILE_BODY]] ], [ -10, %[[WHILE_BODY_PREHEADER]] ]156; CHECK-NEXT: [[COUNT_012:%.*]] = phi i32 [ [[INC:%.*]], %[[WHILE_BODY]] ], [ 0, %[[WHILE_BODY_PREHEADER]] ]157; CHECK-NEXT: [[FOO_ADDR_011:%.*]] = phi ptr [ [[INCDEC_PTR2:%.*]], %[[WHILE_BODY]] ], [ [[FOO]], %[[WHILE_BODY_PREHEADER]] ]158; CHECK-NEXT: [[STR_ADDR_010:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY]] ], [ [[STR]], %[[WHILE_BODY_PREHEADER]] ]159; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[STR_ADDR_010]], i64 1160; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[COUNT_012]], 1161; CHECK-NEXT: [[INC1]] = add nsw i32 [[COUNT_OFFSET_013]], 1162; CHECK-NEXT: [[ADD]] = add nuw nsw i32 [[COUNT_MULTIPLE_014]], 2163; CHECK-NEXT: [[INCDEC_PTR2]] = getelementptr inbounds nuw i8, ptr [[FOO_ADDR_011]], i64 1164; CHECK-NEXT: [[TMP10:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1165; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP10]], 0166; CHECK-NEXT: br i1 true, label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY]]167; CHECK: [[WHILE_END_LOOPEXIT]]:168; CHECK-NEXT: br label %[[WHILE_END]]169; CHECK: [[WHILE_END]]:170; CHECK-NEXT: [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[SCEVGEP1]], %[[WHILE_END_LOOPEXIT]] ]171; CHECK-NEXT: [[FOO_ADDR_0_LCSSA:%.*]] = phi ptr [ [[FOO]], %[[ENTRY]] ], [ [[SCEVGEP2]], %[[WHILE_END_LOOPEXIT]] ]172; CHECK-NEXT: [[COUNT_0_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[TMP3]], %[[WHILE_END_LOOPEXIT]] ]173; CHECK-NEXT: [[COUNT_OFFSET_0_LCSSA:%.*]] = phi i32 [ -10, %[[ENTRY]] ], [ [[TMP5]], %[[WHILE_END_LOOPEXIT]] ]174; CHECK-NEXT: [[COUNT_MULTIPLE_0_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[TMP8]], %[[WHILE_END_LOOPEXIT]] ]175; CHECK-NEXT: tail call void @usei(i32 noundef [[COUNT_0_LCSSA]])176; CHECK-NEXT: tail call void @usei(i32 noundef [[COUNT_OFFSET_0_LCSSA]])177; CHECK-NEXT: tail call void @usei(i32 noundef [[COUNT_MULTIPLE_0_LCSSA]])178; CHECK-NEXT: tail call void @use(ptr noundef nonnull [[STR_ADDR_0_LCSSA]])179; CHECK-NEXT: tail call void @use(ptr noundef [[FOO_ADDR_0_LCSSA]])180; CHECK-NEXT: ret void181;182entry:183 %0 = load i8, ptr %str, align 1184 %tobool.not9 = icmp eq i8 %0, 0185 br i1 %tobool.not9, label %while.end, label %while.body186 187while.body:188 %count_multiple.014 = phi i32 [ %add, %while.body ], [ 0, %entry ]189 %count_offset.013 = phi i32 [ %inc1, %while.body ], [ -10, %entry ]190 %count.012 = phi i32 [ %inc, %while.body ], [ 0, %entry ]191 %foo.addr.011 = phi ptr [ %incdec.ptr2, %while.body ], [ %foo, %entry ]192 %str.addr.010 = phi ptr [ %incdec.ptr, %while.body ], [ %str, %entry ]193 %incdec.ptr = getelementptr inbounds nuw i8, ptr %str.addr.010, i64 1194 %inc = add nuw nsw i32 %count.012, 1195 %inc1 = add nsw i32 %count_offset.013, 1196 %add = add nuw nsw i32 %count_multiple.014, 2197 %incdec.ptr2 = getelementptr inbounds nuw i8, ptr %foo.addr.011, i64 1198 %1 = load i8, ptr %incdec.ptr, align 1199 %tobool.not = icmp eq i8 %1, 0200 br i1 %tobool.not, label %while.end, label %while.body201 202while.end:203 %str.addr.0.lcssa = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.body ]204 %foo.addr.0.lcssa = phi ptr [ %foo, %entry ], [ %incdec.ptr2, %while.body ]205 %count.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.body ]206 %count_offset.0.lcssa = phi i32 [ -10, %entry ], [ %inc1, %while.body ]207 %count_multiple.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.body ]208 tail call void @usei(i32 noundef %count.0.lcssa) #3209 tail call void @usei(i32 noundef %count_offset.0.lcssa) #3210 tail call void @usei(i32 noundef %count_multiple.0.lcssa) #3211 tail call void @use(ptr noundef nonnull %str.addr.0.lcssa) #3212 tail call void @use(ptr noundef %foo.addr.0.lcssa) #3213 ret void214}215 216; int valid_strlen_index(const char* str) {217; int i = 0;218; while (str[i]) {219; ++i;220; }221; return i;222; }223define i32 @valid_strlen_index(ptr %str) {224; CHECK-LABEL: define i32 @valid_strlen_index(225; CHECK-SAME: ptr [[STR:%.*]]) {226; CHECK-NEXT: [[ENTRY:.*]]:227; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[STR]])228; CHECK-NEXT: br label %[[WHILE_COND:.*]]229; CHECK: [[WHILE_COND]]:230; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[WHILE_COND]] ], [ 0, %[[ENTRY]] ]231; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[STR]], i64 [[INDVARS_IV]]232; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1233; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP0]], 0234; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1235; CHECK-NEXT: br i1 true, label %[[WHILE_END:.*]], label %[[WHILE_COND]]236; CHECK: [[WHILE_END]]:237; CHECK-NEXT: [[TMP1:%.*]] = trunc nuw nsw i64 [[STRLEN]] to i32238; CHECK-NEXT: ret i32 [[TMP1]]239;240entry:241 br label %while.cond242 243while.cond:244 %indvars.iv = phi i64 [ %indvars.iv.next, %while.cond ], [ 0, %entry ]245 %arrayidx = getelementptr inbounds i8, ptr %str, i64 %indvars.iv246 %0 = load i8, ptr %arrayidx, align 1247 %tobool.not = icmp eq i8 %0, 0248 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1249 br i1 %tobool.not, label %while.end, label %while.cond250 251while.end:252 %1 = trunc nuw nsw i64 %indvars.iv to i32253 ret i32 %1254}255 256; void valid_strlen_offset(const my_char* str) {257; if (*(str++) == '\0') return;258; if (*(str++) == '\0') return;259; if (*(str++) == '\0') return;260; while (*str) {261; ++str;262; }263; use(str);264; }265define dso_local void @valid_strlen_offset(ptr noundef %str) local_unnamed_addr {266; CHECK-LABEL: define dso_local void @valid_strlen_offset(267; CHECK-SAME: ptr noundef [[STR:%.*]]) local_unnamed_addr {268; CHECK-NEXT: [[ENTRY:.*:]]269; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR]], align 1270; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP0]], 0271; CHECK-NEXT: br i1 [[CMP]], label %[[RETURN:.*]], label %[[IF_END:.*]]272; CHECK: [[IF_END]]:273; CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[STR]], i64 1274; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1275; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i8 [[TMP1]], 0276; CHECK-NEXT: br i1 [[CMP4]], label %[[RETURN]], label %[[IF_END7:.*]]277; CHECK: [[IF_END7]]:278; CHECK-NEXT: [[INCDEC_PTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[STR]], i64 2279; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[INCDEC_PTR2]], align 1280; CHECK-NEXT: [[CMP10:%.*]] = icmp eq i8 [[TMP2]], 0281; CHECK-NEXT: br i1 [[CMP10]], label %[[RETURN]], label %[[WHILE_COND_PREHEADER:.*]]282; CHECK: [[WHILE_COND_PREHEADER]]:283; CHECK-NEXT: [[INCDEC_PTR8:%.*]] = getelementptr i8, ptr [[STR]], i64 3284; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[INCDEC_PTR8]])285; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[STRLEN]], 3286; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 [[TMP3]]287; CHECK-NEXT: br label %[[WHILE_COND:.*]]288; CHECK: [[WHILE_COND]]:289; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[INCDEC_PTR14:%.*]], %[[WHILE_COND]] ], [ [[INCDEC_PTR8]], %[[WHILE_COND_PREHEADER]] ]290; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1291; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP4]], 0292; CHECK-NEXT: [[INCDEC_PTR14]] = getelementptr inbounds nuw i8, ptr [[STR_ADDR_0]], i64 1293; CHECK-NEXT: br i1 true, label %[[WHILE_END:.*]], label %[[WHILE_COND]]294; CHECK: [[WHILE_END]]:295; CHECK-NEXT: tail call void @use(ptr noundef nonnull [[SCEVGEP]])296; CHECK-NEXT: br label %[[RETURN]]297; CHECK: [[RETURN]]:298; CHECK-NEXT: ret void299;300entry:301 %0 = load i8, ptr %str, align 1302 %cmp = icmp eq i8 %0, 0303 br i1 %cmp, label %return, label %if.end304 305if.end:306 %incdec.ptr = getelementptr inbounds nuw i8, ptr %str, i64 1307 %1 = load i8, ptr %incdec.ptr, align 1308 %cmp4 = icmp eq i8 %1, 0309 br i1 %cmp4, label %return, label %if.end7310 311if.end7:312 %incdec.ptr2 = getelementptr inbounds nuw i8, ptr %str, i64 2313 %2 = load i8, ptr %incdec.ptr2, align 1314 %cmp10 = icmp eq i8 %2, 0315 br i1 %cmp10, label %return, label %while.cond.preheader316 317while.cond.preheader:318 %incdec.ptr8 = getelementptr inbounds nuw i8, ptr %str, i64 3319 br label %while.cond320 321while.cond:322 %str.addr.0 = phi ptr [ %incdec.ptr14, %while.cond ], [ %incdec.ptr8, %while.cond.preheader ]323 %3 = load i8, ptr %str.addr.0, align 1324 %tobool.not = icmp eq i8 %3, 0325 %incdec.ptr14 = getelementptr inbounds nuw i8, ptr %str.addr.0, i64 1326 br i1 %tobool.not, label %while.end, label %while.cond327 328while.end:329 tail call void @use(ptr noundef nonnull %str.addr.0) #3330 br label %return331 332return:333 ret void334}335 336; void valid_nested_idiom(const char** strs, int n) {337; for (int i = 0; i < n; ++i) {338; const char* s = strs[i];339; int count = 0;340; while (*s) {341; ++s;342; ++count;343; }344; usei(count);345; }346; }347define void @valid_nested_idiom(ptr %strs, i32 %n) {348; CHECK-LABEL: define void @valid_nested_idiom(349; CHECK-SAME: ptr [[STRS:%.*]], i32 [[N:%.*]]) {350; CHECK-NEXT: [[ENTRY:.*:]]351; CHECK-NEXT: [[CMP9:%.*]] = icmp sgt i32 [[N]], 0352; CHECK-NEXT: br i1 [[CMP9]], label %[[FOR_BODY_PREHEADER:.*]], label %[[FOR_COND_CLEANUP:.*]]353; CHECK: [[FOR_BODY_PREHEADER]]:354; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext nneg i32 [[N]] to i64355; CHECK-NEXT: br label %[[FOR_BODY:.*]]356; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]:357; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]]358; CHECK: [[FOR_COND_CLEANUP]]:359; CHECK-NEXT: ret void360; CHECK: [[FOR_BODY]]:361; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, %[[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[WHILE_END:.*]] ]362; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[STRS]], i64 [[INDVARS_IV]]363; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8364; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[TMP0]], align 1365; CHECK-NEXT: [[TOBOOL_NOT6:%.*]] = icmp eq i8 [[TMP1]], 0366; CHECK-NEXT: br i1 [[TOBOOL_NOT6]], label %[[WHILE_END]], label %[[WHILE_BODY_PREHEADER:.*]]367; CHECK: [[WHILE_BODY_PREHEADER]]:368; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 1369; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]])370; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[STRLEN]] to i32371; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], 1372; CHECK-NEXT: br label %[[WHILE_BODY:.*]]373; CHECK: [[WHILE_BODY]]:374; CHECK-NEXT: [[COUNT_08:%.*]] = phi i32 [ [[INC:%.*]], %[[WHILE_BODY]] ], [ 0, %[[WHILE_BODY_PREHEADER]] ]375; CHECK-NEXT: [[S_07:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY]] ], [ [[TMP0]], %[[WHILE_BODY_PREHEADER]] ]376; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[S_07]], i64 1377; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[COUNT_08]], 1378; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[INCDEC_PTR]], align 1379; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i8 [[TMP4]], 0380; CHECK-NEXT: br i1 true, label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY]]381; CHECK: [[WHILE_END_LOOPEXIT]]:382; CHECK-NEXT: br label %[[WHILE_END]]383; CHECK: [[WHILE_END]]:384; CHECK-NEXT: [[COUNT_0_LCSSA:%.*]] = phi i32 [ 0, %[[FOR_BODY]] ], [ [[TMP3]], %[[WHILE_END_LOOPEXIT]] ]385; CHECK-NEXT: tail call void @usei(i32 [[COUNT_0_LCSSA]])386; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1387; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[WIDE_TRIP_COUNT]]388; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], label %[[FOR_BODY]]389;390entry:391 %cmp9 = icmp sgt i32 %n, 0392 br i1 %cmp9, label %for.body.preheader, label %for.cond.cleanup393 394for.body.preheader:395 %wide.trip.count = zext nneg i32 %n to i64396 br label %for.body397 398for.cond.cleanup:399 ret void400 401for.body:402 %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, %while.end ]403 %arrayidx = getelementptr inbounds ptr, ptr %strs, i64 %indvars.iv404 %0 = load ptr, ptr %arrayidx, align 8405 %1 = load i8, ptr %0, align 1406 %tobool.not6 = icmp eq i8 %1, 0407 br i1 %tobool.not6, label %while.end, label %while.body408 409while.body:410 %count.08 = phi i32 [ %inc, %while.body ], [ 0, %for.body ]411 %s.07 = phi ptr [ %incdec.ptr, %while.body ], [ %0, %for.body ]412 %incdec.ptr = getelementptr inbounds nuw i8, ptr %s.07, i64 1413 %inc = add nuw nsw i32 %count.08, 1414 %2 = load i8, ptr %incdec.ptr, align 1415 %tobool.not = icmp eq i8 %2, 0416 br i1 %tobool.not, label %while.end, label %while.body417 418while.end:419 %count.0.lcssa = phi i32 [ 0, %for.body ], [ %inc, %while.body ]420 tail call void @usei(i32 %count.0.lcssa) #2421 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1422 %exitcond.not = icmp eq i64 %indvars.iv.next, %wide.trip.count423 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body424}425 426define i64 @invalid_strlen_has_side_effects(ptr %str) {427; CHECK-LABEL: define i64 @invalid_strlen_has_side_effects(428; CHECK-SAME: ptr [[STR:%.*]]) {429; CHECK-NEXT: [[ENTRY:.*]]:430; CHECK-NEXT: br label %[[WHILE_COND:.*]]431; CHECK: [[WHILE_COND]]:432; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]433; CHECK-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[STR_ADDR_0]], align 1434; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0435; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1436; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]437; CHECK: [[WHILE_END]]:438; CHECK-NEXT: [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]439; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64440; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64441; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]442; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]]443;444entry:445 br label %while.cond446 447while.cond:448 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]449 %0 = load volatile i8, ptr %str.addr.0, align 1450 %cmp.not = icmp eq i8 %0, 0451 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1452 br i1 %cmp.not, label %while.end, label %while.cond453 454while.end:455 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64456 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64457 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast458 ret i64 %sub.ptr.sub459}460 461 462define i8 @invalid_exit_phi_scev(ptr %str) {463; CHECK-LABEL: define i8 @invalid_exit_phi_scev(464; CHECK-SAME: ptr [[STR:%.*]]) {465; CHECK-NEXT: [[ENTRY:.*]]:466; CHECK-NEXT: br label %[[WHILE_COND:.*]]467; CHECK: [[WHILE_COND]]:468; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]469; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1470; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0471; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1472; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]473; CHECK: [[WHILE_END]]:474; CHECK-NEXT: [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]475; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi i8 [ [[TMP0]], %[[WHILE_COND]] ]476; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64477; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64478; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]479; CHECK-NEXT: ret i8 [[DOTLCSSA]]480;481entry:482 br label %while.cond483 484while.cond:485 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]486 %0 = load i8, ptr %str.addr.0, align 1487 %cmp.not = icmp eq i8 %0, 0488 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1489 br i1 %cmp.not, label %while.end, label %while.cond490 491while.end:492 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64493 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64494 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast495 496 ; %0.lcssa has invalid scev rec {%0} expected to be {%str,+,constant}497 ret i8 %0498}499 500 501 502define i64 @invalid_branch_cond(ptr %str) {503; CHECK-LABEL: define i64 @invalid_branch_cond(504; CHECK-SAME: ptr [[STR:%.*]]) {505; CHECK-NEXT: [[ENTRY:.*]]:506; CHECK-NEXT: br label %[[WHILE_COND:.*]]507; CHECK: [[WHILE_COND]]:508; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]509; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1510; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 10511; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1512; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]513; CHECK: [[WHILE_END]]:514; CHECK-NEXT: [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]515; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64516; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64517; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]518; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]]519;520entry:521 br label %while.cond522 523while.cond:524 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]525 %0 = load i8, ptr %str.addr.0, align 1526 527 ; We compare against '\n' instead of '\0'528 %cmp.not = icmp eq i8 %0, 10529 530 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1531 br i1 %cmp.not, label %while.end, label %while.cond532 533while.end:534 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64535 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64536 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast537 ret i64 %sub.ptr.sub538}539 540define i64 @invalid_unknown_step_size(ptr %str, i64 %step) {541; CHECK-LABEL: define i64 @invalid_unknown_step_size(542; CHECK-SAME: ptr [[STR:%.*]], i64 [[STEP:%.*]]) {543; CHECK-NEXT: [[ENTRY:.*]]:544; CHECK-NEXT: br label %[[WHILE_COND:.*]]545; CHECK: [[WHILE_COND]]:546; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]547; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1548; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0549; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 [[STEP]]550; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]551; CHECK: [[WHILE_END]]:552; CHECK-NEXT: [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]553; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64554; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64555; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]556; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]]557;558entry:559 br label %while.cond560 561while.cond:562 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]563 %0 = load i8, ptr %str.addr.0, align 1564 %cmp.not = icmp eq i8 %0, 0565 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 %step566 br i1 %cmp.not, label %while.end, label %while.cond567 568while.end:569 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64570 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64571 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast572 ret i64 %sub.ptr.sub573}574 575declare ptr @pure(ptr) #0;576attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }577 578define i64 @invalid_add_rec(ptr %str) {579; CHECK-LABEL: define i64 @invalid_add_rec(580; CHECK-SAME: ptr [[STR:%.*]]) {581; CHECK-NEXT: [[ENTRY:.*]]:582; CHECK-NEXT: br label %[[WHILE_COND:.*]]583; CHECK: [[WHILE_COND]]:584; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]585; CHECK-NEXT: [[INDIRECT:%.*]] = tail call ptr @pure(ptr [[STR_ADDR_0]])586; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[INDIRECT]], align 1587; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0588; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1589; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_COND]]590; CHECK: [[WHILE_END]]:591; CHECK-NEXT: [[STR_ADDR_0_LCSSA:%.*]] = phi ptr [ [[STR_ADDR_0]], %[[WHILE_COND]] ]592; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[STR_ADDR_0_LCSSA]] to i64593; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64594; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]]595; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]]596;597entry:598 br label %while.cond599 600while.cond:601 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]602 %indirect = tail call ptr @pure(ptr %str.addr.0)603 %0 = load i8, ptr %indirect, align 1604 %cmp.not = icmp eq i8 %0, 0605 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1606 br i1 %cmp.not, label %while.end, label %while.cond607 608while.end:609 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64610 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64611 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast612 ret i64 %sub.ptr.sub613}614 615define i64 @valid_basic_strlen_with_dbg(ptr %str) {616; Make sure that the call to strlen has debug info attached.617; CHECK-LABEL: define i64 @valid_basic_strlen_with_dbg(618; CHECK-SAME: ptr [[STR:%.*]]) {619; CHECK-NEXT: [[ENTRY:.*]]:620; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[STR]]), !dbg [[DBGLOC1:![0-9]+]]621; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[STR]], i64 [[STRLEN]]622; CHECK-NEXT: br label %[[WHILE_COND:.*]]623; CHECK: [[WHILE_COND]]:624; CHECK-NEXT: [[STR_ADDR_0:%.*]] = phi ptr [ [[STR]], %[[ENTRY]] ], [ [[INCDEC_PTR:%.*]], %[[WHILE_COND]] ]625; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR_ADDR_0]], align 1, !dbg [[DBGLOC2:![0-9]+]]626; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[TMP0]], 0, !dbg [[DBGLOC2]]627; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr i8, ptr [[STR_ADDR_0]], i64 1, !dbg [[DBGLOC2]]628; CHECK-NEXT: br i1 true, label %[[WHILE_END:.*]], label %[[WHILE_COND]], !dbg [[DBGLOC1]]629; CHECK: [[WHILE_END]]:630; CHECK-NEXT: [[SUB_PTR_LHS_CAST:%.*]] = ptrtoint ptr [[SCEVGEP]] to i64, !dbg [[DBGLOC2]]631; CHECK-NEXT: [[SUB_PTR_RHS_CAST:%.*]] = ptrtoint ptr [[STR]] to i64, !dbg [[DBGLOC2]]632; CHECK-NEXT: [[SUB_PTR_SUB:%.*]] = sub i64 [[SUB_PTR_LHS_CAST]], [[SUB_PTR_RHS_CAST]], !dbg [[DBGLOC2]]633; CHECK-NEXT: ret i64 [[SUB_PTR_SUB]], !dbg [[DBGLOC2]]634;635; CHECK: [[DBGLOC1]] = !DILocation(line: 3, column: 3636; CHECK: [[DBGLOC2]] = !DILocation(line: 5, column: 3637;638entry:639 br label %while.cond640 641while.cond:642 %str.addr.0 = phi ptr [ %str, %entry ], [ %incdec.ptr, %while.cond ]643 %0 = load i8, ptr %str.addr.0, align 1, !dbg !8644 %cmp.not = icmp eq i8 %0, 0, !dbg !8645 %incdec.ptr = getelementptr i8, ptr %str.addr.0, i64 1, !dbg !8646 br i1 %cmp.not, label %while.end, label %while.cond, !dbg !4647 648while.end:649 %sub.ptr.lhs.cast = ptrtoint ptr %str.addr.0 to i64, !dbg !8650 %sub.ptr.rhs.cast = ptrtoint ptr %str to i64, !dbg !8651 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast, !dbg !8652 ret i64 %sub.ptr.sub, !dbg !8653}654 655!llvm.module.flags = !{!0}656!llvm.dbg.cu = !{!1}657 658!0 = !{i32 1, !"Debug Info Version", i32 3}659!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)660!2 = !DIFile(filename: "strlen.c", directory: "/tmp")661!3 = !{}662!4 = !DILocation(line: 3, column: 3, scope: !5)663!5 = distinct !DILexicalBlock(scope: !6, file: !2, line: 2, column: 21)664!6 = distinct !DISubprogram(name: "foo", scope: !2, file: !2, line: 2, type: !7, virtualIndex: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !1)665!7 = !DISubroutineType(types: !3)666!8 = !DILocation(line: 5, column: 3, scope: !5)667