1; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -irce-allow-unsigned-latch=true -S < %s 2>&1 | FileCheck %s 2 3; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 4; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 5; CHECK: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 6; CHECK: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 7; CHECK-NOT: irce: in function test_05: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 8; CHECK: irce: in function test_06: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> 9 10; UGT condition for increasing loop. 11define void @test_01(i32* %arr, i32* %a_len_ptr) #0 { 12 13; CHECK: test_01( 14; CHECK: entry: 15; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0 16; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at 17; CHECK-NEXT: br i1 [[COND]], label %loop.preheader, label %main.pseudo.exit 18; CHECK: loop: 19; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ] 20; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1 21; CHECK-NEXT: %abc = icmp ult i32 %idx, %exit.mainloop.at 22; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 23; CHECK-NOT: loop.preloop: 24; CHECK: loop.postloop: 25; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] 26; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1 27; CHECK-NEXT: %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at 28; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit 29 30entry: 31 %len = load i32, i32* %a_len_ptr, !range !0 32 br label %loop 33 34loop: 35 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] 36 %idx.next = add nsw nuw i32 %idx, 1 37 %abc = icmp ult i32 %idx, %len 38 br i1 %abc, label %in.bounds, label %out.of.bounds 39 40in.bounds: 41 %addr = getelementptr i32, i32* %arr, i32 %idx 42 store i32 0, i32* %addr 43 %next = icmp ugt i32 %idx.next, 100 44 br i1 %next, label %exit, label %loop 45 46out.of.bounds: 47 ret void 48 49exit: 50 ret void 51} 52 53; UGT condition for decreasing loop. 54define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { 55 56; CHECK: test_02( 57; CHECK: entry: 58; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 59; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1 60; CHECK-NEXT: %umax = select i1 [[COND1]], i32 %len, i32 1 61; CHECK-NEXT: %exit.preloop.at = add i32 %umax, -1 62; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ugt i32 100, %exit.preloop.at 63; CHECK-NEXT: br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit 64; CHECK: mainloop: 65; CHECK-NEXT: br label %loop 66; CHECK: loop: 67; CHECK-NEXT: %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ] 68; CHECK-NEXT: %idx.next = add i32 %idx, -1 69; CHECK-NEXT: %abc = icmp ult i32 %idx, %len 70; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 71; CHECK-NOT: loop.postloop: 72; CHECK: loop.preloop: 73; CHECK-NEXT: %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ 100, %loop.preloop.preheader ] 74; CHECK-NEXT: %idx.next.preloop = add i32 %idx.preloop, -1 75; CHECK-NEXT: %abc.preloop = icmp ult i32 %idx.preloop, %len 76; CHECK-NEXT: br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit 77 78entry: 79 %len = load i32, i32* %a_len_ptr, !range !0 80 br label %loop 81 82loop: 83 %idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ] 84 %idx.next = add i32 %idx, -1 85 %abc = icmp ult i32 %idx, %len 86 br i1 %abc, label %in.bounds, label %out.of.bounds 87 88in.bounds: 89 %addr = getelementptr i32, i32* %arr, i32 %idx 90 store i32 0, i32* %addr 91 %next = icmp ugt i32 %idx.next, 0 92 br i1 %next, label %loop, label %exit 93 94out.of.bounds: 95 ret void 96 97exit: 98 ret void 99} 100 101; Check SINT_MAX + 1, test is similar to test_01. 102define void @test_03(i32* %arr, i32* %a_len_ptr) #0 { 103 104; CHECK: test_03( 105; CHECK: entry: 106; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0 107; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at 108; CHECK-NEXT: br i1 [[COND]], label %loop.preheader, label %main.pseudo.exit 109; CHECK: loop: 110; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ] 111; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1 112; CHECK-NEXT: %abc = icmp ult i32 %idx, %exit.mainloop.at 113; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 114; CHECK-NOT: loop.preloop: 115; CHECK: loop.postloop: 116; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] 117; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1 118; CHECK-NEXT: %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at 119; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit 120 121entry: 122 %len = load i32, i32* %a_len_ptr, !range !0 123 br label %loop 124 125loop: 126 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] 127 %idx.next = add nsw nuw i32 %idx, 1 128 %abc = icmp ult i32 %idx, %len 129 br i1 %abc, label %in.bounds, label %out.of.bounds 130 131in.bounds: 132 %addr = getelementptr i32, i32* %arr, i32 %idx 133 store i32 0, i32* %addr 134 %next = icmp ugt i32 %idx.next, 2147483648 135 br i1 %next, label %exit, label %loop 136 137out.of.bounds: 138 ret void 139 140exit: 141 ret void 142} 143 144; Check SINT_MAX + 1, test is similar to test_02. 145define void @test_04(i32* %arr, i32* %a_len_ptr) #0 { 146 147; CHECK: test_04( 148; CHECK: entry: 149; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 150; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1 151; CHECK-NEXT: %umax = select i1 [[COND1]], i32 %len, i32 1 152; CHECK-NEXT: %exit.preloop.at = add i32 %umax, -1 153; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ugt i32 -2147483648, %exit.preloop.at 154; CHECK-NEXT: br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit 155; CHECK: mainloop: 156; CHECK-NEXT: br label %loop 157; CHECK: loop: 158; CHECK-NEXT: %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ] 159; CHECK-NEXT: %idx.next = add i32 %idx, -1 160; CHECK-NEXT: %abc = icmp ult i32 %idx, %len 161; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 162; CHECK-NOT: loop.postloop: 163; CHECK: loop.preloop: 164; CHECK-NEXT: %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ -2147483648, %loop.preloop.preheader ] 165; CHECK-NEXT: %idx.next.preloop = add i32 %idx.preloop, -1 166; CHECK-NEXT: %abc.preloop = icmp ult i32 %idx.preloop, %len 167; CHECK-NEXT: br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit 168 169entry: 170 %len = load i32, i32* %a_len_ptr, !range !0 171 br label %loop 172 173loop: 174 %idx = phi i32 [ 2147483648, %entry ], [ %idx.next, %in.bounds ] 175 %idx.next = add i32 %idx, -1 176 %abc = icmp ult i32 %idx, %len 177 br i1 %abc, label %in.bounds, label %out.of.bounds 178 179in.bounds: 180 %addr = getelementptr i32, i32* %arr, i32 %idx 181 store i32 0, i32* %addr 182 %next = icmp ugt i32 %idx.next, 0 183 br i1 %next, label %loop, label %exit 184 185out.of.bounds: 186 ret void 187 188exit: 189 ret void 190} 191 192; Increasing loop, UINT_MAX. Negative test: we cannot add 1 to UINT_MAX. 193define void @test_05(i32* %arr, i32* %a_len_ptr) #0 { 194 195; CHECK: test_05( 196; CHECK-NOT: loop.preloop: 197; CHECK-NOT: loop.postloop: 198 199entry: 200 %len = load i32, i32* %a_len_ptr, !range !0 201 br label %loop 202 203loop: 204 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] 205 %idx.next = add nsw nuw i32 %idx, 1 206 %abc = icmp ult i32 %idx, %len 207 br i1 %abc, label %in.bounds, label %out.of.bounds 208 209in.bounds: 210 %addr = getelementptr i32, i32* %arr, i32 %idx 211 store i32 0, i32* %addr 212 %next = icmp ugt i32 %idx.next, 4294967295 213 br i1 %next, label %exit, label %loop 214 215out.of.bounds: 216 ret void 217 218exit: 219 ret void 220} 221 222; Decreasing loop, UINT_MAX. Positive test. 223define void @test_06(i32* %arr, i32* %a_len_ptr) #0 { 224 225; CHECK: test_06( 226; CHECK: mainloop: 227; CHECK-NEXT: br label %loop 228; CHECK: loop: 229; CHECK-NEXT: %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ] 230; CHECK-NEXT: %idx.next = add nuw i32 %idx, -1 231; CHECK-NEXT: %abc = icmp ult i32 %idx, %len 232; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 233; CHECK-NOT: loop.postloop: 234; CHECK: loop.preloop: 235; CHECK-NEXT: %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ -1, %loop.preloop.preheader ] 236; CHECK-NEXT: %idx.next.preloop = add nuw i32 %idx.preloop, -1 237; CHECK-NEXT: %abc.preloop = icmp ult i32 %idx.preloop, %len 238; CHECK-NEXT: br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit 239 240entry: 241 %len = load i32, i32* %a_len_ptr, !range !0 242 br label %loop 243 244loop: 245 %idx = phi i32 [ 4294967295, %entry ], [ %idx.next, %in.bounds ] 246 %idx.next = add nuw i32 %idx, -1 247 %abc = icmp ult i32 %idx, %len 248 br i1 %abc, label %in.bounds, label %out.of.bounds 249 250in.bounds: 251 %addr = getelementptr i32, i32* %arr, i32 %idx 252 store i32 0, i32* %addr 253 %next = icmp ugt i32 %idx.next, 0 254 br i1 %next, label %loop, label %exit 255 256out.of.bounds: 257 ret void 258 259exit: 260 ret void 261} 262 263!0 = !{i32 0, i32 50} 264