llvm.org GIT mirror
[LoopPredication] Handle the case when the guard and the latch IV have different offsets This is a follow up change for D37569. Currently the transformation is limited to the case when: * The loop has a single latch with the condition of the form: ++i <pred> latchLimit, where <pred> is u<, u<=, s<, or s<=. * The step of the IV used in the latch condition is 1. * The IV of the latch condition is the same as the post increment IV of the guard condition. * The guard condition is of the form i u< guardLimit. This patch enables the transform in the case when the latch is latchStart + i <pred> latchLimit, where <pred> is u<, u<=, s<, or s<=. And the guard is guardStart + i u< guardLimit Reviewed By: anna Differential Revision: https://reviews.llvm.org/D39097 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316768 91177308-0d34-0410-b5e6-96231b3b80d8 Artur Pilipenko 1 year, 10 months ago
2 changed file(s) with 328 addition(s) and 71 deletion(s).
 52 52 // One of the ways to reason about this problem is to use an inductive proof 53 53 // approach. Given the loop: 54 54 // 55 // if (B(Start)) {⏎ 55 // if (B(0)) {⏎ 56 56 // do { 57 // I = PHI(Start, I.INC)⏎ 57 // I = PHI(0, I.INC)⏎ 58 58 // I.INC = I + Step 59 59 // guard(G(I)); 60 // } while (B(I.INC));⏎ 60 // } while (B(I));⏎ 61 61 // } 62 62 // 63 63 // where B(x) and G(x) are predicates that map integers to booleans, we want a 64 64 // loop invariant expression M such the following program has the same semantics 65 65 // as the above: 66 66 // 67 // if (B(Start)) {⏎ 67 // if (B(0)) {⏎ 68 68 // do { 69 // I = PHI(Start, I.INC)⏎ 69 // I = PHI(0, I.INC)⏎ 70 70 // I.INC = I + Step 71 // guard(G(Start) && M); 72 // } while (B(I.INC));⏎ 71 // guard(G(0) && M);⏎ 72 // } while (B(I)); 73 73 // } 74 74 // 75 // One solution for M is M = forall X . (G(X) && B(X + Step)) => G(X + Step) ⏎ 75 // One solution for M is M = forall X . (G(X) && B(X)) => G(X + Step)⏎ 76 76 // 77 77 // Informal proof that the transformation above is correct: 78 78 // 79 79 // By the definition of guards we can rewrite the guard condition to: 80 // G(I) && G(Start) && M⏎ 80 // G(I) && G(0) && M⏎ 81 81 // 82 82 // Let's prove that for each iteration of the loop: 83 // G(Start) && M => G(I)⏎ 83 // G(0) && M => G(I)⏎ 84 84 // And the condition above can be simplified to G(Start) && M. 85 85 // 86 86 // Induction base. 87 // G(Start) && M => G(Start) 88 // 89 // Induction step. Assuming G(Start) && M => G(I) on the subsequent ⏎ 87 // G(0) && M => G(0)⏎ 88 // 89 // Induction step. Assuming G(0) && M => G(I) on the subsequent 90 90 // iteration: 91 91 // 92 // B(I + Step) is true because it's the backedge condition.⏎ 92 // B(I) is true because it's the backedge condition.⏎ 93 93 // G(I) is true because the backedge is guarded by this condition. 94 94 // 95 // So M = forall X . (G(X) && B(X + Step)) => G(X + Step) implies 96 // G(I + Step).⏎ 95 // So M = forall X . (G(X) && B(X)) => G(X + Step) implies G(I + Step).⏎ 97 96 // 98 97 // Note that we can use anything stronger than M, i.e. any condition which 99 98 // implies M. 100 99 // 101 100 // For now the transformation is limited to the following case: 102 101 // * The loop has a single latch with the condition of the form: 103 // ++i latchLimit, where is u<, u<=, s<, or s<=.⏎ 102 // B(X) = latchStart + X latchLimit,⏎ 103 // where is u<, u<=, s<, or s<=. 104 104 // * The step of the IV used in the latch condition is 1. 105 // * The IV of the latch condition is the same as the post increment IV of the 106 // guard condition. 107 // * The guard condition is 108 // i u< guardLimit.⏎ 105 // * The guard condition is of the form⏎ 106 // G(X) = guardStart + X u< guardLimit 109 107 // 110 108 // For the ult latch comparison case M is: 111 // forall X . X u< guardLimit && (X + 1) u< latchLimit => 112 // (X + 1) u< guardLimit 113 // 114 // This is true if latchLimit u<= guardLimit since then 115 // (X + 1) u< latchLimit u<= guardLimit == (X + 1) u< guardLimit. 116 // 117 // So for ult condition the widened condition is: 118 // i.start u< guardLimit && latchLimit u<= guardLimit 119 // Similarly for ule condition the widened condition is: 120 // i.start u< guardLimit && latchLimit u< guardLimit 121 // 122 // For the signed latch comparison case M is: 123 // forall X . X u< guardLimit && (X + 1) s< latchLimit => 124 // (X + 1) u< guardLimit 125 // 126 // The only way the antecedent can be true and the consequent can be false is ⏎ 109 // forall X . guardStart + X u< guardLimit && latchStart + X ⏎ 110 // guardStart + X + 1 u< guardLimit 111 // 112 // The only way the antecedent can be true and the consequent can be false is 127 113 // if 128 // X == guardLimit - 1⏎ 114 // X == guardLimit - 1 - guardStart⏎ 129 115 // (and guardLimit is non-zero, but we won't use this latter fact). 130 // If X == guardLimit - 1 then the second half of the antecedent is 131 // guardLimit s< latchLimit⏎ 116 // If X == guardLimit - 1 - guardStart then the second half of the antecedent is⏎ 117 // latchStart + guardLimit - 1 - guardStart u< latchLimit 132 118 // and its negation is 133 // latchLimit s<= guardLimit. 134 // 135 // In other words, if latchLimit s<= guardLimit then:⏎ 119 // latchStart + guardLimit - 1 - guardStart u>= latchLimit⏎ 120 // 121 // In other words, if 122 // latchLimit u<= latchStart + guardLimit - 1 - guardStart 123 // then: 136 124 // (the ranges below are written in ConstantRange notation, where [A, B) is the 137 125 // set for (I = A; I != B; I++ /*maywrap*/) yield(I);) 138 126 // 139 // forall X . X u< guardLimit && (X + 1) s< latchLimit => (X + 1) u< guardLimit 140 // == forall X . X u< guardLimit && (X + 1) s< guardLimit => (X + 1) u< guardLimit 141 // == forall X . X in [0, guardLimit) && (X + 1) in [INT_MIN, guardLimit) => (X + 1) in [0, guardLimit) 142 // == forall X . X in [0, guardLimit) && X in [INT_MAX, guardLimit-1) => X in [-1, guardLimit-1) 143 // == forall X . X in [0, guardLimit-1) => X in [-1, guardLimit-1)⏎ 127 // forall X . guardStart + X u< guardLimit &&⏎ 128 // latchStart + X u< latchLimit => 129 // guardStart + X + 1 u< guardLimit 130 // == forall X . guardStart + X u< guardLimit && 131 // latchStart + X u< latchStart + guardLimit - 1 - guardStart => 132 // guardStart + X + 1 u< guardLimit 133 // == forall X . (guardStart + X) in [0, guardLimit) && 134 // (latchStart + X) in [0, latchStart + guardLimit - 1 - guardStart) => 135 // (guardStart + X + 1) in [0, guardLimit) 136 // == forall X . X in [-guardStart, guardLimit - guardStart) && 137 // X in [-latchStart, guardLimit - 1 - guardStart) => 138 // X in [-guardStart - 1, guardLimit - guardStart - 1) 144 139 // == true 145 140 // 146 141 // So the widened condition is: 147 // i.start u< guardLimit && latchLimit s<= guardLimit 148 // Similarly for sle condition the widened condition is: 149 // i.start u< guardLimit && latchLimit s< guardLimit⏎ 142 // guardStart u< guardLimit &&⏎ 143 // latchStart + guardLimit - 1 - guardStart u>= latchLimit 144 // Similarly for ule condition the widened condition is: 145 // guardStart u< guardLimit && 146 // latchStart + guardLimit - 1 - guardStart u> latchLimit 147 // For slt condition the widened condition is: 148 // guardStart u< guardLimit && 149 // latchStart + guardLimit - 1 - guardStart s>= latchLimit 150 // For sle condition the widened condition is: 151 // guardStart u< guardLimit && 152 // latchStart + guardLimit - 1 - guardStart s> latchLimit 150 153 // 151 154 //===----------------------------------------------------------------------===// 152 155 321 324 return None; 322 325 } 323 326 auto *RangeCheckIV = RangeCheck->IV; 324 auto *PostIncRangeCheckIV = RangeCheckIV->getPostIncExpr(*SE); 325 if (LatchCheck.IV != PostIncRangeCheckIV) { 326 DEBUG(dbgs() << "Post increment range check IV (" << *PostIncRangeCheckIV 327 << ") is not the same as latch IV (" << *LatchCheck.IV 328 << ")!\n"); 329 return None; 330 } 331 assert(RangeCheckIV->getStepRecurrence(*SE)->isOne() && "must be one"); 332 const SCEV *Start = RangeCheckIV->getStart();⏎ 327 auto *Ty = RangeCheckIV->getType();⏎ 328 if (Ty != LatchCheck.IV->getType()) { 329 DEBUG(dbgs() << "Type mismatch between range check and latch IVs!\n"); 330 return None; 331 } 332 if (!RangeCheckIV->isAffine()) { 333 DEBUG(dbgs() << "Range check IV is not affine!\n"); 334 return None; 335 } 336 auto *Step = RangeCheckIV->getStepRecurrence(*SE); 337 if (Step != LatchCheck.IV->getStepRecurrence(*SE)) { 338 DEBUG(dbgs() << "Range check and latch have IVs different steps!\n"); 339 return None; 340 } 341 assert(Step->isOne() && "must be one"); 333 342 334 343 // Generate the widened condition: 335 // i.start u< guardLimit && latchLimit guardLimit⏎ 344 // guardStart u< guardLimit &&⏎ 345 // latchLimit guardLimit - 1 - guardStart + latchStart 336 346 // where depends on the latch condition predicate. See the file 337 347 // header comment for the reasoning. 348 const SCEV *GuardStart = RangeCheckIV->getStart(); 349 const SCEV *GuardLimit = RangeCheck->Limit; 350 const SCEV *LatchStart = LatchCheck.IV->getStart(); 351 const SCEV *LatchLimit = LatchCheck.Limit; 352 353 // guardLimit - guardStart + latchStart - 1 354 const SCEV *RHS = 355 SE->getAddExpr(SE->getMinusSCEV(GuardLimit, GuardStart), 356 SE->getMinusSCEV(LatchStart, SE->getOne(Ty))); 357 338 358 ICmpInst::Predicate LimitCheckPred; 339 359 switch (LatchCheck.Pred) { 340 360 case ICmpInst::ICMP_ULT: 353 373 llvm_unreachable("Unsupported loop latch!"); 354 374 } 355 375 376 DEBUG(dbgs() << "LHS: " << *LatchLimit << "\n"); 377 DEBUG(dbgs() << "RHS: " << *RHS << "\n"); 378 DEBUG(dbgs() << "Pred: " << LimitCheckPred << "\n"); 379 356 380 auto CanExpand = [this](const SCEV *S) { 357 381 return SE->isLoopInvariant(S, L) && isSafeToExpand(S, *SE); 358 382 }; 359 if (!CanExpand(Start) || !CanExpand(LatchCheck.Limit) || 360 !CanExpand(RangeCheck->Limit)) 361 return None;⏎ 383 if (!CanExpand(GuardStart) || !CanExpand(GuardLimit) ||⏎ 384 !CanExpand(LatchLimit) || !CanExpand(RHS)) { 385 DEBUG(dbgs() << "Can't expand limit check!\n"); 386 return None; 387 } 362 388 363 389 Instruction *InsertAt = Preheader->getTerminator(); 364 auto *LimitCheck = expandCheck(Expander, Builder, LimitCheckPred, 365 LatchCheck.Limit, RangeCheck->Limit, InsertAt);⏎ 390 auto *LimitCheck =⏎ 391 expandCheck(Expander, Builder, LimitCheckPred, LatchLimit, RHS, InsertAt); 366 392 auto *FirstIterationCheck = expandCheck(Expander, Builder, RangeCheck->Pred, 367 Start, RangeCheck->Limit, InsertAt);⏎ 393 GuardStart, GuardLimit, InsertAt);⏎ 368 394 return Builder.CreateAnd(FirstIterationCheck, LimitCheck); 369 395 } 370 396
 247 247 248 248 %i.next = add nuw i32 %i, 1 249 249 %continue = icmp sle i32 %i.next, %n 250 br i1 %continue, label %loop, label %exit 251 252 exit: 253 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ] 254 ret i32 %result 255 } 256 257 define i32 @signed_loop_0_to_n_preincrement_latch_check(i32* %array, i32 %length, i32 %n) { 258 ; CHECK-LABEL: @signed_loop_0_to_n_preincrement_latch_check 259 entry: 260 %tmp5 = icmp sle i32 %n, 0 261 br i1 %tmp5, label %exit, label %loop.preheader 262 263 loop.preheader: 264 ; CHECK: loop.preheader: 265 ; CHECK: [[length_minus_1:[^ ]+]] = add i32 %length, -1 266 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp sle i32 %n, [[length_minus_1]] 267 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 0, %length 268 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]] 269 ; CHECK-NEXT: br label %loop 270 br label %loop 271 272 loop: 273 ; CHECK: loop: 274 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ] 275 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 276 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ] 277 %within.bounds = icmp ult i32 %i, %length 278 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 279 280 %i.i64 = zext i32 %i to i64 281 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64 282 %array.i = load i32, i32* %array.i.ptr, align 4 283 %loop.acc.next = add i32 %loop.acc, %array.i 284 285 %i.next = add i32 %i, 1 286 %continue = icmp slt i32 %i, %n 287 br i1 %continue, label %loop, label %exit 288 289 exit: 290 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ] 291 ret i32 %result 292 } 293 294 define i32 @signed_loop_0_to_n_preincrement_latch_check_postincrement_guard_check(i32* %array, i32 %length, i32 %n) { 295 ; CHECK-LABEL: @signed_loop_0_to_n_preincrement_latch_check_postincrement_guard_check 296 entry: 297 %tmp5 = icmp sle i32 %n, 0 298 br i1 %tmp5, label %exit, label %loop.preheader 299 300 loop.preheader: 301 ; CHECK: loop.preheader: 302 ; CHECK: [[length_minus_2:[^ ]+]] = add i32 %length, -2 303 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp sle i32 %n, [[length_minus_2]] 304 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 1, %length 305 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]] 306 ; CHECK-NEXT: br label %loop 307 br label %loop 308 309 loop: 310 ; CHECK: loop: 311 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ] 312 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 313 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ] 314 315 %i.next = add i32 %i, 1 316 %within.bounds = icmp ult i32 %i.next, %length 317 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 318 319 %i.i64 = zext i32 %i to i64 320 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64 321 %array.i = load i32, i32* %array.i.ptr, align 4 322 %loop.acc.next = add i32 %loop.acc, %array.i 323 324 %continue = icmp slt i32 %i, %n 325 br i1 %continue, label %loop, label %exit 326 327 exit: 328 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ] 329 ret i32 %result 330 } 331 332 define i32 @signed_loop_0_to_n_sle_latch_offset_ult_check(i32* %array, i32 %length, i32 %n) { 333 ; CHECK-LABEL: @signed_loop_0_to_n_sle_latch_offset_ult_check 334 entry: 335 %tmp5 = icmp sle i32 %n, 0 336 br i1 %tmp5, label %exit, label %loop.preheader 337 338 loop.preheader: 339 ; CHECK: loop.preheader: 340 ; CHECK: [[length_minus_1:[^ ]+]] = add i32 %length, -1 341 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp slt i32 %n, [[length_minus_1]] 342 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 1, %length 343 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]] 344 ; CHECK-NEXT: br label %loop 345 br label %loop 346 347 loop: 348 ; CHECK: loop: 349 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ] 350 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 351 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ] 352 %i.offset = add i32 %i, 1 353 %within.bounds = icmp ult i32 %i.offset, %length 354 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 355 356 %i.i64 = zext i32 %i to i64 357 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64 358 %array.i = load i32, i32* %array.i.ptr, align 4 359 %loop.acc.next = add i32 %loop.acc, %array.i 360 361 %i.next = add i32 %i, 1 362 %continue = icmp sle i32 %i.next, %n 363 br i1 %continue, label %loop, label %exit 364 365 exit: 366 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ] 367 ret i32 %result 368 } 369 370 define i32 @signed_loop_0_to_n_offset_sle_latch_offset_ult_check(i32* %array, i32 %length, i32 %n) { 371 ; CHECK-LABEL: @signed_loop_0_to_n_offset_sle_latch_offset_ult_check 372 entry: 373 %tmp5 = icmp sle i32 %n, 0 374 br i1 %tmp5, label %exit, label %loop.preheader 375 376 loop.preheader: 377 ; CHECK: loop.preheader: 378 ; CHECK: [[limit_check:[^ ]+]] = icmp slt i32 %n, %length 379 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 1, %length 380 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]] 381 ; CHECK-NEXT: br label %loop 382 br label %loop 383 384 loop: 385 ; CHECK: loop: 386 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ] 387 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 388 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ] 389 %i.offset = add i32 %i, 1 390 %within.bounds = icmp ult i32 %i.offset, %length 391 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 392 393 %i.i64 = zext i32 %i to i64 394 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64 395 %array.i = load i32, i32* %array.i.ptr, align 4 396 %loop.acc.next = add i32 %loop.acc, %array.i 397 398 %i.next = add i32 %i, 1 399 %i.next.offset = add i32 %i.next, 1 400 %continue = icmp sle i32 %i.next.offset, %n 250 401 br i1 %continue, label %loop, label %exit 251 402 252 403 exit: 361 512 ret i32 %result 362 513 } 363 514 364 define i32 @signed_loop_0_to_n_unrelated_iv_range_check(i32* %array, i32 %start, i32 %length, i32 %n) { 365 ; CHECK-LABEL: @signed_loop_0_to_n_unrelated_iv_range_check⏎ 515 define i32 @signed_loop_start_to_n_offset_iv_range_check(i32* %array, i32 %start.i,⏎ 516 i32 %start.j, i32 %length, 517 i32 %n) { 518 ; CHECK-LABEL: @signed_loop_start_to_n_offset_iv_range_check 519 entry: 520 %tmp5 = icmp sle i32 %n, 0 521 br i1 %tmp5, label %exit, label %loop.preheader 522 523 loop.preheader: 524 ; CHECK: loop.preheader: 525 ; CHECK: [[length_plus_start_i:[^ ]+]] = add i32 %length, %start.i 526 ; CHECK-NEXT: [[limit:[^ ]+]] = sub i32 [[length_plus_start_i]], %start.j 527 ; CHECK-NEXT: [[limit_check:[^ ]+]] = icmp sle i32 %n, [[limit]] 528 ; CHECK-NEXT: [[first_iteration_check:[^ ]+]] = icmp ult i32 %start.j, %length 529 ; CHECK-NEXT: [[wide_cond:[^ ]+]] = and i1 [[first_iteration_check]], [[limit_check]] 530 ; CHECK-NEXT: br label %loop 531 br label %loop 532 533 loop: 534 ; CHECK: loop: 535 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ] 536 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 537 %i = phi i32 [ %i.next, %loop ], [ %start.i, %loop.preheader ] 538 %j = phi i32 [ %j.next, %loop ], [ %start.j, %loop.preheader ] 539 540 %within.bounds = icmp ult i32 %j, %length 541 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 542 543 %i.i64 = zext i32 %i to i64 544 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64 545 %array.i = load i32, i32* %array.i.ptr, align 4 546 %loop.acc.next = add i32 %loop.acc, %array.i 547 548 %j.next = add i32 %j, 1 549 %i.next = add i32 %i, 1 550 %continue = icmp slt i32 %i.next, %n 551 br i1 %continue, label %loop, label %exit 552 553 exit: 554 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ] 555 ret i32 %result 556 } 557 558 define i32 @signed_loop_0_to_n_different_iv_types(i32* %array, i16 %length, i32 %n) { 559 ; CHECK-LABEL: @signed_loop_0_to_n_different_iv_types 560 entry: 561 %tmp5 = icmp sle i32 %n, 0 562 br i1 %tmp5, label %exit, label %loop.preheader 563 564 loop.preheader: 565 ; CHECK: loop.preheader: 566 ; CHECK-NEXT: br label %loop 567 br label %loop 568 569 loop: 570 ; CHECK: loop: 571 ; CHECK: %within.bounds = icmp ult i16 %j, %length 572 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 573 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 574 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ] 575 %j = phi i16 [ %j.next, %loop ], [ 0, %loop.preheader ] 576 577 %within.bounds = icmp ult i16 %j, %length 578 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 579 580 %i.i64 = zext i32 %i to i64 581 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64 582 %array.i = load i32, i32* %array.i.ptr, align 4 583 %loop.acc.next = add i32 %loop.acc, %array.i 584 585 %j.next = add i16 %j, 1 586 %i.next = add i32 %i, 1 587 %continue = icmp slt i32 %i.next, %n 588 br i1 %continue, label %loop, label %exit 589 590 exit: 591 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ] 592 ret i32 %result 593 } 594 595 define i32 @signed_loop_0_to_n_different_iv_strides(i32* %array, i32 %length, i32 %n) { 596 ; CHECK-LABEL: @signed_loop_0_to_n_different_iv_strides 366 597 entry: 367 598 %tmp5 = icmp sle i32 %n, 0 368 599 br i1 %tmp5, label %exit, label %loop.preheader 378 609 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 379 610 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ] 380 611 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ] 381 %j = phi i32 [ %j.next, %loop ], [ %start, %loop.preheader ]⏎ 612 %j = phi i32 [ %j.next, %loop ], [ 0, %loop.preheader ]⏎ 382 613 383 614 %within.bounds = icmp ult i32 %j, %length 384 615 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ] 388 619 %array.i = load i32, i32* %array.i.ptr, align 4 389 620 %loop.acc.next = add i32 %loop.acc, %array.i 390 621 391 %j.next = add nsw i32 %j, 1⏎ 622 %j.next = add nsw i32 %j, 2⏎ 392 623 %i.next = add nsw i32 %i, 1 393 624 %continue = icmp slt i32 %i.next, %n 394 625 br i1 %continue, label %loop, label %exit