1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3 2; RUN: opt -verify-loop-info -irce-print-changed-loops -passes=irce -S < %s 2>&1 | FileCheck %s 3; RUN: opt -verify-loop-info -irce-print-changed-loops -passes='require<branch-prob>,irce' -S < %s 2>&1 | FileCheck %s 4 5; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 6; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 7; CHECK: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 8; CHECK: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 9; CHECK-NOT: irce: in function test_05: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 10; CHECK: irce: in function test_06: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 11 12; UGT condition for increasing loop. 13define void @test_01(ptr %arr, ptr %a_len_ptr) #0 { 14; CHECK-LABEL: define void @test_01 15; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { 16; CHECK-NEXT: entry: 17; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0:![0-9]+]] 18; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 0, [[EXIT_MAINLOOP_AT]] 19; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] 20; CHECK: loop.preheader: 21; CHECK-NEXT: br label [[LOOP:%.*]] 22; CHECK: loop: 23; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] 24; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i32 [[IDX]], 1 25; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[EXIT_MAINLOOP_AT]] 26; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] 27; CHECK: in.bounds: 28; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] 29; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 30; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 100 31; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] 32; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true 33; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_EXIT_SELECTOR:%.*]], label [[LOOP]] 34; CHECK: main.exit.selector: 35; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] 36; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[IDX_NEXT_LCSSA]], 101 37; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] 38; CHECK: main.pseudo.exit: 39; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] 40; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] 41; CHECK-NEXT: br label [[POSTLOOP:%.*]] 42; CHECK: out.of.bounds.loopexit: 43; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] 44; CHECK: out.of.bounds.loopexit1: 45; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] 46; CHECK: out.of.bounds: 47; CHECK-NEXT: ret void 48; CHECK: exit.loopexit: 49; CHECK-NEXT: br label [[EXIT]] 50; CHECK: exit: 51; CHECK-NEXT: ret void 52; CHECK: postloop: 53; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] 54; CHECK: loop.postloop: 55; CHECK-NEXT: [[IDX_POSTLOOP:%.*]] = phi i32 [ [[IDX_COPY]], [[POSTLOOP]] ], [ [[IDX_NEXT_POSTLOOP:%.*]], [[IN_BOUNDS_POSTLOOP:%.*]] ] 56; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw nsw i32 [[IDX_POSTLOOP]], 1 57; CHECK-NEXT: [[ABC_POSTLOOP:%.*]] = icmp ult i32 [[IDX_POSTLOOP]], [[EXIT_MAINLOOP_AT]] 58; CHECK-NEXT: br i1 [[ABC_POSTLOOP]], label [[IN_BOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] 59; CHECK: in.bounds.postloop: 60; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_POSTLOOP]] 61; CHECK-NEXT: store i32 0, ptr [[ADDR_POSTLOOP]], align 4 62; CHECK-NEXT: [[NEXT_POSTLOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_POSTLOOP]], 100 63; CHECK-NEXT: br i1 [[NEXT_POSTLOOP]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_POSTLOOP]], !llvm.loop [[LOOP1:![0-9]+]], !loop_constrainer.loop.clone [[META6:![0-9]+]] 64; 65 66entry: 67 %len = load i32, ptr %a_len_ptr, !range !0 68 br label %loop 69 70loop: 71 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] 72 %idx.next = add nsw nuw i32 %idx, 1 73 %abc = icmp ult i32 %idx, %len 74 br i1 %abc, label %in.bounds, label %out.of.bounds 75 76in.bounds: 77 %addr = getelementptr i32, ptr %arr, i32 %idx 78 store i32 0, ptr %addr 79 %next = icmp ugt i32 %idx.next, 100 80 br i1 %next, label %exit, label %loop 81 82out.of.bounds: 83 ret void 84 85exit: 86 ret void 87} 88 89; UGT condition for decreasing loop. 90define void @test_02(ptr %arr, ptr %a_len_ptr) #0 { 91; CHECK-LABEL: define void @test_02 92; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { 93; CHECK-NEXT: entry: 94; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] 95; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[LEN]], i32 1) 96; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = add nsw i32 [[UMAX]], -1 97; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 100, [[EXIT_PRELOOP_AT]] 98; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]] 99; CHECK: loop.preloop.preheader: 100; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]] 101; CHECK: mainloop: 102; CHECK-NEXT: br label [[LOOP:%.*]] 103; CHECK: loop: 104; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PRELOOP_COPY:%.*]], [[MAINLOOP:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] 105; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], -1 106; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[LEN]] 107; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] 108; CHECK: in.bounds: 109; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] 110; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 111; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 0 112; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] 113; CHECK: out.of.bounds.loopexit: 114; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] 115; CHECK: out.of.bounds.loopexit1: 116; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] 117; CHECK: out.of.bounds: 118; CHECK-NEXT: ret void 119; CHECK: exit.loopexit: 120; CHECK-NEXT: br label [[EXIT:%.*]] 121; CHECK: exit: 122; CHECK-NEXT: ret void 123; CHECK: loop.preloop: 124; CHECK-NEXT: [[IDX_PRELOOP:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP:%.*]], [[IN_BOUNDS_PRELOOP:%.*]] ], [ 100, [[LOOP_PRELOOP_PREHEADER]] ] 125; CHECK-NEXT: [[IDX_NEXT_PRELOOP]] = add i32 [[IDX_PRELOOP]], -1 126; CHECK-NEXT: [[ABC_PRELOOP:%.*]] = icmp ult i32 [[IDX_PRELOOP]], [[LEN]] 127; CHECK-NEXT: br i1 [[ABC_PRELOOP]], label [[IN_BOUNDS_PRELOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] 128; CHECK: in.bounds.preloop: 129; CHECK-NEXT: [[ADDR_PRELOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_PRELOOP]] 130; CHECK-NEXT: store i32 0, ptr [[ADDR_PRELOOP]], align 4 131; CHECK-NEXT: [[NEXT_PRELOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], 0 132; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], [[EXIT_PRELOOP_AT]] 133; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop [[LOOP7:![0-9]+]], !loop_constrainer.loop.clone [[META6]] 134; CHECK: preloop.exit.selector: 135; CHECK-NEXT: [[IDX_NEXT_PRELOOP_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP]], [[IN_BOUNDS_PRELOOP]] ] 136; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP_LCSSA]], 0 137; CHECK-NEXT: br i1 [[TMP2]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]] 138; CHECK: preloop.pseudo.exit: 139; CHECK-NEXT: [[IDX_PRELOOP_COPY]] = phi i32 [ 100, [[ENTRY:%.*]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] 140; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 100, [[ENTRY]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] 141; CHECK-NEXT: br label [[MAINLOOP]] 142; 143 144entry: 145 %len = load i32, ptr %a_len_ptr, !range !0 146 br label %loop 147 148loop: 149 %idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ] 150 %idx.next = add i32 %idx, -1 151 %abc = icmp ult i32 %idx, %len 152 br i1 %abc, label %in.bounds, label %out.of.bounds 153 154in.bounds: 155 %addr = getelementptr i32, ptr %arr, i32 %idx 156 store i32 0, ptr %addr 157 %next = icmp ugt i32 %idx.next, 0 158 br i1 %next, label %loop, label %exit 159 160out.of.bounds: 161 ret void 162 163exit: 164 ret void 165} 166 167; Check SINT_MAX + 1, test is similar to test_01. 168define void @test_03(ptr %arr, ptr %a_len_ptr) #0 { 169; CHECK-LABEL: define void @test_03 170; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { 171; CHECK-NEXT: entry: 172; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] 173; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 0, [[EXIT_MAINLOOP_AT]] 174; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] 175; CHECK: loop.preheader: 176; CHECK-NEXT: br label [[LOOP:%.*]] 177; CHECK: loop: 178; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ] 179; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i32 [[IDX]], 1 180; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[EXIT_MAINLOOP_AT]] 181; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] 182; CHECK: in.bounds: 183; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] 184; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 185; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], -2147483648 186; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] 187; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], true 188; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_EXIT_SELECTOR:%.*]], label [[LOOP]] 189; CHECK: main.exit.selector: 190; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] 191; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[IDX_NEXT_LCSSA]], -2147483647 192; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]] 193; CHECK: main.pseudo.exit: 194; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] 195; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] 196; CHECK-NEXT: br label [[POSTLOOP:%.*]] 197; CHECK: out.of.bounds.loopexit: 198; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] 199; CHECK: out.of.bounds.loopexit1: 200; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] 201; CHECK: out.of.bounds: 202; CHECK-NEXT: ret void 203; CHECK: exit.loopexit: 204; CHECK-NEXT: br label [[EXIT]] 205; CHECK: exit: 206; CHECK-NEXT: ret void 207; CHECK: postloop: 208; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]] 209; CHECK: loop.postloop: 210; CHECK-NEXT: [[IDX_POSTLOOP:%.*]] = phi i32 [ [[IDX_COPY]], [[POSTLOOP]] ], [ [[IDX_NEXT_POSTLOOP:%.*]], [[IN_BOUNDS_POSTLOOP:%.*]] ] 211; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw nsw i32 [[IDX_POSTLOOP]], 1 212; CHECK-NEXT: [[ABC_POSTLOOP:%.*]] = icmp ult i32 [[IDX_POSTLOOP]], [[EXIT_MAINLOOP_AT]] 213; CHECK-NEXT: br i1 [[ABC_POSTLOOP]], label [[IN_BOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] 214; CHECK: in.bounds.postloop: 215; CHECK-NEXT: [[ADDR_POSTLOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_POSTLOOP]] 216; CHECK-NEXT: store i32 0, ptr [[ADDR_POSTLOOP]], align 4 217; CHECK-NEXT: [[NEXT_POSTLOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_POSTLOOP]], -2147483648 218; CHECK-NEXT: br i1 [[NEXT_POSTLOOP]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_POSTLOOP]], !llvm.loop [[LOOP8:![0-9]+]], !loop_constrainer.loop.clone [[META6]] 219; 220 221entry: 222 %len = load i32, ptr %a_len_ptr, !range !0 223 br label %loop 224 225loop: 226 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] 227 %idx.next = add nsw nuw i32 %idx, 1 228 %abc = icmp ult i32 %idx, %len 229 br i1 %abc, label %in.bounds, label %out.of.bounds 230 231in.bounds: 232 %addr = getelementptr i32, ptr %arr, i32 %idx 233 store i32 0, ptr %addr 234 %next = icmp ugt i32 %idx.next, 2147483648 235 br i1 %next, label %exit, label %loop 236 237out.of.bounds: 238 ret void 239 240exit: 241 ret void 242} 243 244; Check SINT_MAX + 1, test is similar to test_02. 245define void @test_04(ptr %arr, ptr %a_len_ptr) #0 { 246; CHECK-LABEL: define void @test_04 247; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { 248; CHECK-NEXT: entry: 249; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] 250; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[LEN]], i32 1) 251; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = add nsw i32 [[UMAX]], -1 252; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 -2147483648, [[EXIT_PRELOOP_AT]] 253; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]] 254; CHECK: loop.preloop.preheader: 255; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]] 256; CHECK: mainloop: 257; CHECK-NEXT: br label [[LOOP:%.*]] 258; CHECK: loop: 259; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PRELOOP_COPY:%.*]], [[MAINLOOP:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] 260; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], -1 261; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[LEN]] 262; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] 263; CHECK: in.bounds: 264; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] 265; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 266; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 0 267; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] 268; CHECK: out.of.bounds.loopexit: 269; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] 270; CHECK: out.of.bounds.loopexit1: 271; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] 272; CHECK: out.of.bounds: 273; CHECK-NEXT: ret void 274; CHECK: exit.loopexit: 275; CHECK-NEXT: br label [[EXIT:%.*]] 276; CHECK: exit: 277; CHECK-NEXT: ret void 278; CHECK: loop.preloop: 279; CHECK-NEXT: [[IDX_PRELOOP:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP:%.*]], [[IN_BOUNDS_PRELOOP:%.*]] ], [ -2147483648, [[LOOP_PRELOOP_PREHEADER]] ] 280; CHECK-NEXT: [[IDX_NEXT_PRELOOP]] = add i32 [[IDX_PRELOOP]], -1 281; CHECK-NEXT: [[ABC_PRELOOP:%.*]] = icmp ult i32 [[IDX_PRELOOP]], [[LEN]] 282; CHECK-NEXT: br i1 [[ABC_PRELOOP]], label [[IN_BOUNDS_PRELOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] 283; CHECK: in.bounds.preloop: 284; CHECK-NEXT: [[ADDR_PRELOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_PRELOOP]] 285; CHECK-NEXT: store i32 0, ptr [[ADDR_PRELOOP]], align 4 286; CHECK-NEXT: [[NEXT_PRELOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], 0 287; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], [[EXIT_PRELOOP_AT]] 288; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop [[LOOP9:![0-9]+]], !loop_constrainer.loop.clone [[META6]] 289; CHECK: preloop.exit.selector: 290; CHECK-NEXT: [[IDX_NEXT_PRELOOP_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP]], [[IN_BOUNDS_PRELOOP]] ] 291; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP_LCSSA]], 0 292; CHECK-NEXT: br i1 [[TMP2]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]] 293; CHECK: preloop.pseudo.exit: 294; CHECK-NEXT: [[IDX_PRELOOP_COPY]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] 295; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] 296; CHECK-NEXT: br label [[MAINLOOP]] 297; 298 299entry: 300 %len = load i32, ptr %a_len_ptr, !range !0 301 br label %loop 302 303loop: 304 %idx = phi i32 [ 2147483648, %entry ], [ %idx.next, %in.bounds ] 305 %idx.next = add i32 %idx, -1 306 %abc = icmp ult i32 %idx, %len 307 br i1 %abc, label %in.bounds, label %out.of.bounds 308 309in.bounds: 310 %addr = getelementptr i32, ptr %arr, i32 %idx 311 store i32 0, ptr %addr 312 %next = icmp ugt i32 %idx.next, 0 313 br i1 %next, label %loop, label %exit 314 315out.of.bounds: 316 ret void 317 318exit: 319 ret void 320} 321 322; Increasing loop, UINT_MAX. Negative test: we cannot add 1 to UINT_MAX. 323define void @test_05(ptr %arr, ptr %a_len_ptr) #0 { 324; CHECK-LABEL: define void @test_05 325; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { 326; CHECK-NEXT: entry: 327; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] 328; CHECK-NEXT: br label [[LOOP:%.*]] 329; CHECK: loop: 330; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] 331; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i32 [[IDX]], 1 332; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[LEN]] 333; CHECK-NEXT: br i1 [[ABC]], label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS:%.*]] 334; CHECK: in.bounds: 335; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] 336; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 337; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], -1 338; CHECK-NEXT: br i1 [[NEXT]], label [[EXIT:%.*]], label [[LOOP]] 339; CHECK: out.of.bounds: 340; CHECK-NEXT: ret void 341; CHECK: exit: 342; CHECK-NEXT: ret void 343; 344 345entry: 346 %len = load i32, ptr %a_len_ptr, !range !0 347 br label %loop 348 349loop: 350 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] 351 %idx.next = add nsw nuw i32 %idx, 1 352 %abc = icmp ult i32 %idx, %len 353 br i1 %abc, label %in.bounds, label %out.of.bounds 354 355in.bounds: 356 %addr = getelementptr i32, ptr %arr, i32 %idx 357 store i32 0, ptr %addr 358 %next = icmp ugt i32 %idx.next, 4294967295 359 br i1 %next, label %exit, label %loop 360 361out.of.bounds: 362 ret void 363 364exit: 365 ret void 366} 367 368; Decreasing loop, UINT_MAX. Positive test. 369define void @test_06(ptr %arr, ptr %a_len_ptr) #0 { 370; CHECK-LABEL: define void @test_06 371; CHECK-SAME: (ptr [[ARR:%.*]], ptr [[A_LEN_PTR:%.*]]) { 372; CHECK-NEXT: entry: 373; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A_LEN_PTR]], align 4, !range [[RNG0]] 374; CHECK-NEXT: br i1 true, label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]] 375; CHECK: loop.preloop.preheader: 376; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]] 377; CHECK: mainloop: 378; CHECK-NEXT: br label [[LOOP:%.*]] 379; CHECK: loop: 380; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PRELOOP_COPY:%.*]], [[MAINLOOP:%.*]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ] 381; CHECK-NEXT: [[IDX_NEXT]] = add nuw i32 [[IDX]], -1 382; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[LEN]] 383; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT1:%.*]] 384; CHECK: in.bounds: 385; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]] 386; CHECK-NEXT: store i32 0, ptr [[ADDR]], align 4 387; CHECK-NEXT: [[NEXT:%.*]] = icmp ugt i32 [[IDX_NEXT]], 0 388; CHECK-NEXT: br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] 389; CHECK: out.of.bounds.loopexit: 390; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] 391; CHECK: out.of.bounds.loopexit1: 392; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] 393; CHECK: out.of.bounds: 394; CHECK-NEXT: ret void 395; CHECK: exit.loopexit: 396; CHECK-NEXT: br label [[EXIT:%.*]] 397; CHECK: exit: 398; CHECK-NEXT: ret void 399; CHECK: loop.preloop: 400; CHECK-NEXT: [[IDX_PRELOOP:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP:%.*]], [[IN_BOUNDS_PRELOOP:%.*]] ], [ -1, [[LOOP_PRELOOP_PREHEADER]] ] 401; CHECK-NEXT: [[IDX_NEXT_PRELOOP]] = add nuw i32 [[IDX_PRELOOP]], -1 402; CHECK-NEXT: [[ABC_PRELOOP:%.*]] = icmp ult i32 [[IDX_PRELOOP]], [[LEN]] 403; CHECK-NEXT: br i1 [[ABC_PRELOOP]], label [[IN_BOUNDS_PRELOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] 404; CHECK: in.bounds.preloop: 405; CHECK-NEXT: [[ADDR_PRELOOP:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX_PRELOOP]] 406; CHECK-NEXT: store i32 0, ptr [[ADDR_PRELOOP]], align 4 407; CHECK-NEXT: [[NEXT_PRELOOP:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], 0 408; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP]], 0 409; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop [[LOOP10:![0-9]+]], !loop_constrainer.loop.clone [[META6]] 410; CHECK: preloop.exit.selector: 411; CHECK-NEXT: [[IDX_NEXT_PRELOOP_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT_PRELOOP]], [[IN_BOUNDS_PRELOOP]] ] 412; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[IDX_NEXT_PRELOOP_LCSSA]], 0 413; CHECK-NEXT: br i1 [[TMP1]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]] 414; CHECK: preloop.pseudo.exit: 415; CHECK-NEXT: [[IDX_PRELOOP_COPY]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] 416; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ -1, [[ENTRY]] ], [ [[IDX_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ] 417; CHECK-NEXT: br label [[MAINLOOP]] 418; 419 420entry: 421 %len = load i32, ptr %a_len_ptr, !range !0 422 br label %loop 423 424loop: 425 %idx = phi i32 [ 4294967295, %entry ], [ %idx.next, %in.bounds ] 426 %idx.next = add nuw i32 %idx, -1 427 %abc = icmp ult i32 %idx, %len 428 br i1 %abc, label %in.bounds, label %out.of.bounds 429 430in.bounds: 431 %addr = getelementptr i32, ptr %arr, i32 %idx 432 store i32 0, ptr %addr 433 %next = icmp ugt i32 %idx.next, 0 434 br i1 %next, label %loop, label %exit 435 436out.of.bounds: 437 ret void 438 439exit: 440 ret void 441} 442 443!0 = !{i32 0, i32 50} 444;. 445; CHECK: [[RNG0]] = !{i32 0, i32 50} 446; CHECK: [[LOOP1]] = distinct !{[[LOOP1]], [[META2:![0-9]+]], [[META3:![0-9]+]], [[META4:![0-9]+]], [[META5:![0-9]+]]} 447; CHECK: [[META2]] = !{!"llvm.loop.unroll.disable"} 448; CHECK: [[META3]] = !{!"llvm.loop.vectorize.enable", i1 false} 449; CHECK: [[META4]] = !{!"llvm.loop.licm_versioning.disable"} 450; CHECK: [[META5]] = !{!"llvm.loop.distribute.enable", i1 false} 451; CHECK: [[META6]] = !{} 452; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META3]], [[META4]], [[META5]]} 453; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META2]], [[META3]], [[META4]], [[META5]]} 454; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META2]], [[META3]], [[META4]], [[META5]]} 455; CHECK: [[LOOP10]] = distinct !{[[LOOP10]], [[META2]], [[META3]], [[META4]], [[META5]]} 456;. 457