1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -mtriple=x86_64-linux -codegenprepare -S < %s | FileCheck %s 3 4define i32 @test_01(ptr %p, i64 %len, i32 %x) { 5; CHECK-LABEL: @test_01( 6; CHECK-NEXT: entry: 7; CHECK-NEXT: br label [[LOOP:%.*]] 8; CHECK: loop: 9; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 10; CHECK-NEXT: [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1) 11; CHECK-NEXT: [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0 12; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1 13; CHECK-NEXT: br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]] 14; CHECK: backedge: 15; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4 16; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 17; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4 18; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 19; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]] 20; CHECK: exit: 21; CHECK-NEXT: ret i32 -1 22; CHECK: failure: 23; CHECK-NEXT: unreachable 24; 25entry: 26 %scevgep = getelementptr i32, ptr %p, i64 -1 27 br label %loop 28 29loop: ; preds = %backedge, %entry 30 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 31 %iv.next = add i64 %iv, -1 32 %cond_1 = icmp eq i64 %iv, 0 33 br i1 %cond_1, label %exit, label %backedge 34 35backedge: ; preds = %loop 36 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 37 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 38 %cond_2 = icmp eq i32 %loaded, %x 39 br i1 %cond_2, label %failure, label %loop 40 41exit: ; preds = %loop 42 ret i32 -1 43 44failure: ; preds = %backedge 45 unreachable 46} 47 48; Similar to test_01, but with different offset. 49define i32 @test_01a(ptr %p, i64 %len, i32 %x) { 50; CHECK-LABEL: @test_01a( 51; CHECK-NEXT: entry: 52; CHECK-NEXT: br label [[LOOP:%.*]] 53; CHECK: loop: 54; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 55; CHECK-NEXT: [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1) 56; CHECK-NEXT: [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0 57; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1 58; CHECK-NEXT: br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]] 59; CHECK: backedge: 60; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4 61; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 62; CHECK-NEXT: [[SUNKADDR2:%.*]] = getelementptr i8, ptr [[SUNKADDR1]], i64 -24 63; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR2]] unordered, align 4 64; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 65; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]] 66; CHECK: exit: 67; CHECK-NEXT: ret i32 -1 68; CHECK: failure: 69; CHECK-NEXT: unreachable 70; 71entry: 72 %scevgep = getelementptr i32, ptr %p, i64 -7 73 br label %loop 74 75loop: ; preds = %backedge, %entry 76 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 77 %iv.next = add i64 %iv, -1 78 %cond_1 = icmp eq i64 %iv, 0 79 br i1 %cond_1, label %exit, label %backedge 80 81backedge: ; preds = %loop 82 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 83 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 84 %cond_2 = icmp eq i32 %loaded, %x 85 br i1 %cond_2, label %failure, label %loop 86 87exit: ; preds = %loop 88 ret i32 -1 89 90failure: ; preds = %backedge 91 unreachable 92} 93 94; TODO: We can use trick with usub here. 95define i32 @test_02(ptr %p, i64 %len, i32 %x) { 96; CHECK-LABEL: @test_02( 97; CHECK-NEXT: entry: 98; CHECK-NEXT: br label [[LOOP:%.*]] 99; CHECK: loop: 100; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 101; CHECK-NEXT: [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1) 102; CHECK-NEXT: [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0 103; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1 104; CHECK-NEXT: br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]] 105; CHECK: backedge: 106; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4 107; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 108; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4 109; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 110; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]] 111; CHECK: exit: 112; CHECK-NEXT: ret i32 -1 113; CHECK: failure: 114; CHECK-NEXT: unreachable 115; 116entry: 117 %scevgep = getelementptr i32, ptr %p, i64 -1 118 br label %loop 119 120loop: ; preds = %backedge, %entry 121 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 122 %cond_1 = icmp eq i64 %iv, 0 123 br i1 %cond_1, label %exit, label %backedge 124 125backedge: ; preds = %loop 126 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 127 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 128 %cond_2 = icmp eq i32 %loaded, %x 129 %iv.next = add i64 %iv, -1 130 br i1 %cond_2, label %failure, label %loop 131 132exit: ; preds = %loop 133 ret i32 -1 134 135failure: ; preds = %backedge 136 unreachable 137} 138 139declare i1 @use(i64 %x) 140declare i1 @some_cond() 141 142; Make sure we do not move the increment below the point where it is used. 143define i32 @test_03_neg(ptr %p, i64 %len, i32 %x) { 144; CHECK-LABEL: @test_03_neg( 145; CHECK-NEXT: entry: 146; CHECK-NEXT: br label [[LOOP:%.*]] 147; CHECK: loop: 148; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 149; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], -1 150; CHECK-NEXT: [[COND_0:%.*]] = call i1 @use(i64 [[IV_NEXT]]) 151; CHECK-NEXT: br i1 [[COND_0]], label [[MIDDLE:%.*]], label [[FAILURE:%.*]] 152; CHECK: middle: 153; CHECK-NEXT: [[COND_1:%.*]] = icmp eq i64 [[IV]], 0 154; CHECK-NEXT: br i1 [[COND_1]], label [[EXIT:%.*]], label [[BACKEDGE]] 155; CHECK: backedge: 156; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[IV_NEXT]], 4 157; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 158; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4 159; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 160; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE]], label [[LOOP]] 161; CHECK: exit: 162; CHECK-NEXT: ret i32 -1 163; CHECK: failure: 164; CHECK-NEXT: unreachable 165; 166entry: 167 %scevgep = getelementptr i32, ptr %p, i64 -1 168 br label %loop 169 170loop: ; preds = %backedge, %entry 171 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 172 %iv.next = add i64 %iv, -1 173 %cond_0 = call i1 @use(i64 %iv.next) 174 br i1 %cond_0, label %middle, label %failure 175 176middle: 177 %cond_1 = icmp eq i64 %iv, 0 178 br i1 %cond_1, label %exit, label %backedge 179 180backedge: ; preds = %loop 181 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 182 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 183 %cond_2 = icmp eq i32 %loaded, %x 184 br i1 %cond_2, label %failure, label %loop 185 186exit: ; preds = %loop 187 ret i32 -1 188 189failure: ; preds = %backedge 190 unreachable 191} 192 193define i32 @test_04_neg(ptr %p, i64 %len, i32 %x) { 194; CHECK-LABEL: @test_04_neg( 195; CHECK-NEXT: entry: 196; CHECK-NEXT: br label [[LOOP:%.*]] 197; CHECK: loop: 198; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 199; CHECK-NEXT: br label [[INNER:%.*]] 200; CHECK: inner: 201; CHECK-NEXT: [[COND_1:%.*]] = icmp eq i64 [[IV]], 0 202; CHECK-NEXT: br i1 [[COND_1]], label [[INNER_BACKEDGE:%.*]], label [[EXIT:%.*]] 203; CHECK: inner_backedge: 204; CHECK-NEXT: [[COND_INNER:%.*]] = call i1 @some_cond() 205; CHECK-NEXT: br i1 [[COND_INNER]], label [[INNER]], label [[BACKEDGE]] 206; CHECK: backedge: 207; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[IV]], 4 208; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 209; CHECK-NEXT: [[SUNKADDR2:%.*]] = getelementptr i8, ptr [[SUNKADDR1]], i64 -4 210; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR2]] unordered, align 4 211; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 212; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], -1 213; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]] 214; CHECK: exit: 215; CHECK-NEXT: ret i32 -1 216; CHECK: failure: 217; CHECK-NEXT: unreachable 218; 219entry: 220 %scevgep = getelementptr i32, ptr %p, i64 -1 221 br label %loop 222 223loop: 224 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 225 br label %inner 226 227inner: 228 %cond_1 = icmp eq i64 %iv, 0 229 br i1 %cond_1, label %inner_backedge, label %exit 230 231inner_backedge: 232 %cond_inner = call i1 @some_cond() 233 br i1 %cond_inner, label %inner, label %backedge 234 235backedge: 236 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 237 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 238 %cond_2 = icmp eq i32 %loaded, %x 239 %iv.next = add i64 %iv, -1 240 br i1 %cond_2, label %failure, label %loop 241 242exit: 243 ret i32 -1 244 245failure: 246 unreachable 247} 248 249; Here Cmp does not dominate latch. 250define i32 @test_05_neg(ptr %p, i64 %len, i32 %x, i1 %cond) { 251; CHECK-LABEL: @test_05_neg( 252; CHECK-NEXT: entry: 253; CHECK-NEXT: br label [[LOOP:%.*]] 254; CHECK: loop: 255; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 256; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], -1 257; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[BACKEDGE]] 258; CHECK: if.true: 259; CHECK-NEXT: [[COND_1:%.*]] = icmp eq i64 [[IV]], 0 260; CHECK-NEXT: br i1 [[COND_1]], label [[EXIT:%.*]], label [[BACKEDGE]] 261; CHECK: backedge: 262; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[IV_NEXT]], 4 263; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 264; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4 265; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 266; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]] 267; CHECK: exit: 268; CHECK-NEXT: ret i32 -1 269; CHECK: failure: 270; CHECK-NEXT: unreachable 271; 272entry: 273 %scevgep = getelementptr i32, ptr %p, i64 -1 274 br label %loop 275 276loop: ; preds = %backedge, %entry 277 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 278 %iv.next = add i64 %iv, -1 279 br i1 %cond, label %if.true, label %backedge 280 281if.true: 282 %cond_1 = icmp eq i64 %iv, 0 283 br i1 %cond_1, label %exit, label %backedge 284 285backedge: ; preds = %loop 286 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 287 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 288 %cond_2 = icmp eq i32 %loaded, %x 289 br i1 %cond_2, label %failure, label %loop 290 291exit: ; preds = %loop 292 ret i32 -1 293 294failure: ; preds = %backedge 295 unreachable 296} 297 298 299; test_01, but with an additional use of %iv.next outside the loop 300define i32 @test_06(ptr %p, i64 %len, i32 %x) { 301; CHECK-LABEL: @test_06( 302; CHECK-NEXT: entry: 303; CHECK-NEXT: br label [[LOOP:%.*]] 304; CHECK: loop: 305; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 306; CHECK-NEXT: [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1) 307; CHECK-NEXT: [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0 308; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1 309; CHECK-NEXT: br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]] 310; CHECK: backedge: 311; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4 312; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 313; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4 314; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 315; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]] 316; CHECK: exit: 317; CHECK-NEXT: ret i32 -1 318; CHECK: failure: 319; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[MATH]] to i32 320; CHECK-NEXT: ret i32 [[TRUNC]] 321; 322entry: 323 %scevgep = getelementptr i32, ptr %p, i64 -1 324 br label %loop 325 326loop: ; preds = %backedge, %entry 327 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 328 %cond_1 = icmp eq i64 %iv, 0 329 br i1 %cond_1, label %exit, label %backedge 330 331backedge: ; preds = %loop 332 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 333 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 334 %iv.next = add i64 %iv, -1 335 %cond_2 = icmp eq i32 %loaded, %x 336 br i1 %cond_2, label %failure, label %loop 337 338exit: 339 ret i32 -1 340 341failure: 342 %trunc = trunc i64 %iv.next to i32 343 ret i32 %trunc 344} 345 346 347; Extra use outside loop which prevents us moving the increment to the cmp 348define i32 @test_07_neg(ptr %p, i64 %len, i32 %x) { 349; CHECK-LABEL: @test_07_neg( 350; CHECK-NEXT: entry: 351; CHECK-NEXT: br label [[LOOP:%.*]] 352; CHECK: loop: 353; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ] 354; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], -1 355; CHECK-NEXT: [[SUNKADDR:%.*]] = mul i64 [[IV_NEXT]], 4 356; CHECK-NEXT: [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]] 357; CHECK-NEXT: [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4 358; CHECK-NEXT: [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]] 359; CHECK-NEXT: br i1 [[COND_2]], label [[FAILURE:%.*]], label [[BACKEDGE]] 360; CHECK: backedge: 361; CHECK-NEXT: [[COND_1:%.*]] = icmp eq i64 [[IV]], 0 362; CHECK-NEXT: br i1 [[COND_1]], label [[EXIT:%.*]], label [[LOOP]] 363; CHECK: exit: 364; CHECK-NEXT: ret i32 -1 365; CHECK: failure: 366; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[IV_NEXT]] to i32 367; CHECK-NEXT: ret i32 [[TRUNC]] 368; 369entry: 370 %scevgep = getelementptr i32, ptr %p, i64 -1 371 br label %loop 372 373loop: 374 %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ] 375 %iv.next = add i64 %iv, -1 376 %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv 377 %loaded = load atomic i32, ptr %scevgep1 unordered, align 4 378 %cond_2 = icmp eq i32 %loaded, %x 379 br i1 %cond_2, label %failure, label %backedge 380 381backedge: 382 %cond_1 = icmp eq i64 %iv, 0 383 br i1 %cond_1, label %exit, label %loop 384 385exit: 386 ret i32 -1 387 388failure: 389 %trunc = trunc i64 %iv.next to i32 390 ret i32 %trunc 391} 392